Progress
This commit is contained in:
parent
e2e7e8c0af
commit
01c8041a6a
@ -86,8 +86,8 @@ export function changeCompose(text, markdown) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function replyCompose(status, routerHistory) {
|
export function replyCompose(status) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: COMPOSE_REPLY,
|
type: COMPOSE_REPLY,
|
||||||
status: status,
|
status: status,
|
||||||
@ -97,8 +97,8 @@ export function replyCompose(status, routerHistory) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function quoteCompose(status, routerHistory) {
|
export function quoteCompose(status) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: COMPOSE_QUOTE,
|
type: COMPOSE_QUOTE,
|
||||||
status: status,
|
status: status,
|
||||||
@ -120,8 +120,8 @@ export function resetCompose() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function mentionCompose(account, routerHistory) {
|
export function mentionCompose(account) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: COMPOSE_MENTION,
|
type: COMPOSE_MENTION,
|
||||||
account: account,
|
account: account,
|
||||||
|
@ -121,7 +121,7 @@ class Account extends ImmutablePureComponent {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{account.get('display_name')}
|
{account.get('display_name')}
|
||||||
{account.get('username')}
|
{`@${account.get('username')}`}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -151,8 +151,8 @@ class Account extends ImmutablePureComponent {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.mt5, _s.mb15].join(' ')}>
|
<div className={[_s.default, _s.px15, _s.py5, _s.backgroundSubtle_onHover, _s.mb5].join(' ')}>
|
||||||
<div className={[_s.default, _s.flexRow].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
|
|
||||||
<NavLink
|
<NavLink
|
||||||
className={[_s.default, _s.noUnderline].join(' ')}
|
className={[_s.default, _s.noUnderline].join(' ')}
|
||||||
@ -165,9 +165,9 @@ class Account extends ImmutablePureComponent {
|
|||||||
<NavLink
|
<NavLink
|
||||||
title={account.get('acct')}
|
title={account.get('acct')}
|
||||||
to={`/${account.get('acct')}`}
|
to={`/${account.get('acct')}`}
|
||||||
className={[_s.default, _s.alignItemsStart, _s.px10, _s.flexGrow1].join(' ')}
|
className={[_s.default, _s.alignItemsStart, _s.noUnderline, _s.px10, _s.flexGrow1].join(' ')}
|
||||||
>
|
>
|
||||||
<DisplayName account={account} multiline={compact} />
|
<DisplayName account={account} isMultiline={compact} />
|
||||||
{!compact && actionButton}
|
{!compact && actionButton}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class AutosuggestAccount extends ImmutablePureComponent {
|
|||||||
<div className='autosuggest-account__icon'>
|
<div className='autosuggest-account__icon'>
|
||||||
<Avatar account={account} size={18} />
|
<Avatar account={account} size={18} />
|
||||||
</div>
|
</div>
|
||||||
<DisplayName account={account} />
|
<DisplayName account={account} noRelationship noHover />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,31 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { autoPlayGif } from '../initial_state'
|
import { autoPlayGif } from '../initial_state'
|
||||||
|
import { openPopover, closePopover } from '../actions/popover'
|
||||||
import Image from './image'
|
import Image from './image'
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
openUserInfoPopover(props) {
|
||||||
|
dispatch(openPopover('USER_INFO', props))
|
||||||
|
},
|
||||||
|
closeUserInfoPopover() {
|
||||||
|
dispatch(closePopover('USER_INFO'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders an avatar component
|
* Renders an avatar component
|
||||||
* @param {map} [props.account] - the account for image
|
* @param {map} [props.account] - the account for image
|
||||||
* @param {number} [props.size=40] - the size of the avatar
|
* @param {number} [props.size=40] - the size of the avatar
|
||||||
*/
|
*/
|
||||||
export default class Avatar extends ImmutablePureComponent {
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
class Avatar extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
account: ImmutablePropTypes.map,
|
account: ImmutablePropTypes.map,
|
||||||
|
noHover: PropTypes.bool,
|
||||||
|
openUserInfoPopover: PropTypes.func.isRequired,
|
||||||
size: PropTypes.number,
|
size: PropTypes.number,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +38,14 @@ export default class Avatar extends ImmutablePureComponent {
|
|||||||
sameImg: !this.props.account ? false : this.props.account.get('avatar') === this.props.account.get('avatar_static'),
|
sameImg: !this.props.account ? false : this.props.account.get('avatar') === this.props.account.get('avatar_static'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateOnProps = [
|
||||||
|
'account',
|
||||||
|
'noHover',
|
||||||
|
'size',
|
||||||
|
]
|
||||||
|
|
||||||
|
mouseOverTimeout = null
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
componentDidUpdate (prevProps) {
|
||||||
if (prevProps.account !== this.props.account) {
|
if (prevProps.account !== this.props.account) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -33,12 +55,30 @@ export default class Avatar extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleMouseEnter = () => {
|
handleMouseEnter = () => {
|
||||||
// : todo : user popover
|
|
||||||
this.setState({ hovering: true })
|
this.setState({ hovering: true })
|
||||||
|
|
||||||
|
if (this.mouseOverTimeout || this.props.noHover) return null
|
||||||
|
this.mouseOverTimeout = setTimeout(() => {
|
||||||
|
this.props.openUserInfoPopover({
|
||||||
|
targetRef: this.node,
|
||||||
|
position: 'top',
|
||||||
|
account: this.props.account,
|
||||||
|
})
|
||||||
|
}, 650)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseLeave = () => {
|
handleMouseLeave = () => {
|
||||||
this.setState({ hovering: false })
|
this.setState({ hovering: false })
|
||||||
|
|
||||||
|
if (this.mouseOverTimeout && !this.props.noHover) {
|
||||||
|
clearTimeout(this.mouseOverTimeout)
|
||||||
|
this.mouseOverTimeout = null
|
||||||
|
this.props.closeUserInfoPopover()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRef = (n) => {
|
||||||
|
this.node = n
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -46,10 +86,14 @@ export default class Avatar extends ImmutablePureComponent {
|
|||||||
const { hovering, sameImg } = this.state
|
const { hovering, sameImg } = this.state
|
||||||
|
|
||||||
const shouldAnimate = autoPlayGif || !sameImg
|
const shouldAnimate = autoPlayGif || !sameImg
|
||||||
|
const isPro = !!account ? account.get('is_pro') : false
|
||||||
|
const alt = !account ? '' : `${account.get('display_name')} ${isPro ? '(PRO)' : ''}`.trim()
|
||||||
|
const classes = [_s.default, _s.circle, _s.overflowHidden]
|
||||||
|
if (isPro) {
|
||||||
|
classes.push(_s.boxShadowAvatarPro)
|
||||||
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
alt: !account ? 'Avatar' : account.get('display_name'),
|
|
||||||
className: [_s.default, _s.circle, _s.overflowHidden].join(' '),
|
|
||||||
onMouseEnter: shouldAnimate ? this.handleMouseEnter : undefined,
|
onMouseEnter: shouldAnimate ? this.handleMouseEnter : undefined,
|
||||||
onMouseLeave: shouldAnimate ? this.handleMouseLeave : undefined,
|
onMouseLeave: shouldAnimate ? this.handleMouseLeave : undefined,
|
||||||
src: !account ? undefined : account.get((hovering || autoPlayGif) ? 'avatar' : 'avatar_static'),
|
src: !account ? undefined : account.get((hovering || autoPlayGif) ? 'avatar' : 'avatar_static'),
|
||||||
@ -61,7 +105,12 @@ export default class Avatar extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Image {...options} />
|
<Image
|
||||||
|
alt={alt}
|
||||||
|
ref={this.setRef}
|
||||||
|
className={classes.join(' ')}
|
||||||
|
{...options}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ export default class Block extends PureComponent {
|
|||||||
const { children } = this.props
|
const { children } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.backgroundColorPrimary, _s.overflowHidden, _s.radiusSmall, _s.borderColorSecondary, _s.border1PX].join(' ')}>
|
<div className={[_s.default, _s.boxShadowBlock, _s.backgroundColorPrimary, _s.overflowHidden, _s.radiusSmall].join(' ')}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -12,10 +12,10 @@ export default class CharacterCounter extends PureComponent {
|
|||||||
max: PropTypes.number.isRequired,
|
max: PropTypes.number.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render() {
|
||||||
const { text, max } = this.props
|
const { text, max } = this.props
|
||||||
|
|
||||||
const actualRadius = '16'
|
const actualRadius = 16
|
||||||
const radius = 12
|
const radius = 12
|
||||||
const circumference = 2 * Math.PI * radius
|
const circumference = 2 * Math.PI * radius
|
||||||
const diff = Math.min(length(text), max) / max
|
const diff = Math.min(length(text), max) / max
|
||||||
@ -23,9 +23,22 @@ export default class CharacterCounter extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.mr10, _s.justifyContentCenter, _s.alignItemsCenter].join(' ')}>
|
<div className={[_s.default, _s.mr10, _s.justifyContentCenter, _s.alignItemsCenter].join(' ')}>
|
||||||
<svg width={actualRadius * 2} height={actualRadius * 2} viewBox={`0 0 ${actualRadius * 2} ${actualRadius * 2}`}>
|
<svg
|
||||||
<circle fill='none' cx={actualRadius} cy={actualRadius} r={radius} fill="none" stroke="#e6e6e6" strokeWidth="2" />
|
width={actualRadius * 2}
|
||||||
<circle style={{
|
height={actualRadius * 2}
|
||||||
|
viewBox={`0 0 ${actualRadius * 2} ${actualRadius * 2}`}
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
fill='none'
|
||||||
|
cx={actualRadius}
|
||||||
|
cy={actualRadius}
|
||||||
|
r={radius}
|
||||||
|
fill='none'
|
||||||
|
stroke='#e6e6e6'
|
||||||
|
strokeWidth='2'
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
style={{
|
||||||
strokeDashoffset: dashoffset,
|
strokeDashoffset: dashoffset,
|
||||||
strokeDasharray: circumference,
|
strokeDasharray: circumference,
|
||||||
}}
|
}}
|
||||||
@ -33,7 +46,7 @@ export default class CharacterCounter extends PureComponent {
|
|||||||
cx={actualRadius}
|
cx={actualRadius}
|
||||||
cy={actualRadius}
|
cy={actualRadius}
|
||||||
r={radius}
|
r={radius}
|
||||||
strokeWidth="2"
|
strokeWidth='2'
|
||||||
strokeLinecap='round'
|
strokeLinecap='round'
|
||||||
stroke='#21cf7a'
|
stroke='#21cf7a'
|
||||||
/>
|
/>
|
||||||
|
@ -60,7 +60,7 @@ export default class ColumnHeader extends PureComponent {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!!actions &&
|
!!actions &&
|
||||||
<div className={[_s.default, _s.backgroundTransparent, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.backgroundTransparent, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.mlAuto].join(' ')}>
|
||||||
{
|
{
|
||||||
actions.map((action, i) => (
|
actions.map((action, i) => (
|
||||||
<Button
|
<Button
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
import { Fragment } from 'react'
|
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { makeGetStatus } from '../selectors';
|
import { makeGetStatus } from '../selectors';
|
||||||
import CommentHeader from './comment_header'
|
|
||||||
import Avatar from './avatar'
|
import Avatar from './avatar'
|
||||||
import Button from './button'
|
import Button from './button'
|
||||||
import DisplayName from './display_name'
|
import CommentHeader from './comment_header'
|
||||||
import DotTextSeperator from './dot_text_seperator'
|
|
||||||
import RelativeTimestamp from './relative_timestamp'
|
|
||||||
import Text from './text'
|
|
||||||
import StatusContent from './status_content'
|
import StatusContent from './status_content'
|
||||||
|
import Text from './text'
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
follow: { id: 'follow', defaultMessage: 'Follow' },
|
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
||||||
|
like: { id: 'status.like', defaultMessage: 'Like' },
|
||||||
})
|
})
|
||||||
|
|
||||||
const makeMapStateToProps = (state, props) => ({
|
const makeMapStateToProps = (state, props) => ({
|
||||||
@ -27,14 +24,23 @@ export default
|
|||||||
class Comment extends ImmutablePureComponent {
|
class Comment extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
indent: PropTypes.number,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
indent: ImmutablePropTypes.number,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
updateOnProps = [
|
||||||
const { status, indent } = this.props
|
'status',
|
||||||
|
'indent',
|
||||||
|
]
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
indent,
|
||||||
|
intl,
|
||||||
|
status,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
console.log("status:", status)
|
|
||||||
const style = {
|
const style = {
|
||||||
paddingLeft: `${indent * 40}px`,
|
paddingLeft: `${indent * 40}px`,
|
||||||
}
|
}
|
||||||
@ -55,58 +61,22 @@ class Comment extends ImmutablePureComponent {
|
|||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexNormal].join(' ')}>
|
<div className={[_s.default, _s.flexNormal].join(' ')}>
|
||||||
<div className={[_s.default, _s.px10, _s.py5, _s.radiusSmall, _s.backgroundSubtle].join(' ')}>
|
<div className={[_s.default, _s.px10, _s.pt5, _s.pb10, _s.radiusSmall, _s.backgroundSubtle].join(' ')}>
|
||||||
<div className={_s.pt2}>
|
<CommentHeader status={status} />
|
||||||
<CommentHeader status={status} />
|
<StatusContent
|
||||||
</div>
|
status={status}
|
||||||
<div className={[_s.py5].join(' ')}>
|
onClick={this.handleClick}
|
||||||
<StatusContent
|
isComment
|
||||||
status={status}
|
collapsable
|
||||||
onClick={this.handleClick}
|
/>
|
||||||
isComment
|
|
||||||
collapsable
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexRow, _s.mt5].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.mt5].join(' ')}>
|
||||||
|
<CommentButton title={intl.formatMessage(messages.like)} />
|
||||||
<Button
|
<CommentButton title={intl.formatMessage(messages.reply)} />
|
||||||
isText
|
<CommentButton title='···' />
|
||||||
radiusSmall
|
|
||||||
backgroundColor='none'
|
|
||||||
color='tertiary'
|
|
||||||
className={[_s.px5, _s.backgroundSubtle_onHover, _s.py2, _s.mr5].join(' ')}
|
|
||||||
>
|
|
||||||
<Text size='extraSmall' color='inherit' weight='bold'>
|
|
||||||
Like
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
isText
|
|
||||||
radiusSmall
|
|
||||||
backgroundColor='none'
|
|
||||||
color='tertiary'
|
|
||||||
className={[_s.px5, _s.backgroundSubtle_onHover, _s.py2, _s.mr5].join(' ')}
|
|
||||||
>
|
|
||||||
<Text size='extraSmall' color='inherit' weight='bold'>
|
|
||||||
Reply
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
isText
|
|
||||||
radiusSmall
|
|
||||||
backgroundColor='none'
|
|
||||||
color='tertiary'
|
|
||||||
className={[_s.px5, _s.backgroundSubtle_onHover, _s.py2, _s.mr5].join(' ')}
|
|
||||||
>
|
|
||||||
<Text size='extraSmall' color='inherit' weight='bold'>
|
|
||||||
···
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -116,3 +86,31 @@ class Comment extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CommentButton extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onClick: PropTypes.func.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { onClick, title } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
isText
|
||||||
|
radiusSmall
|
||||||
|
backgroundColor='none'
|
||||||
|
color='tertiary'
|
||||||
|
className={[_s.px5, _s.backgroundSubtle_onHover, _s.py2, _s.mr5].join(' ')}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
<Text size='extraSmall' color='inherit' weight='bold'>
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,7 +26,7 @@ class CommentHeader extends ImmutablePureComponent {
|
|||||||
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
|
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.alignItemsStart, _s.flexGrow1].join(' ')}>
|
<div className={[_s.default, _s.alignItemsStart, _s.py2, _s.flexGrow1].join(' ')}>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexRow, _s.width100PC, _s.alignItemsCenter].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.width100PC, _s.alignItemsCenter].join(' ')}>
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -34,7 +34,7 @@ class CommentHeader extends ImmutablePureComponent {
|
|||||||
to={`/${status.getIn(['account', 'acct'])}`}
|
to={`/${status.getIn(['account', 'acct'])}`}
|
||||||
title={status.getIn(['account', 'acct'])}
|
title={status.getIn(['account', 'acct'])}
|
||||||
>
|
>
|
||||||
<DisplayName account={status.get('account')} small />
|
<DisplayName account={status.get('account')} isSmall />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ export default class CommentList extends ImmutablePureComponent {
|
|||||||
View more comments
|
View more comments
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.mlAuto].join(' ')}>
|
||||||
<Text color='tertiary'>
|
<Text color='tertiary'>
|
||||||
{max}
|
{max}
|
||||||
of
|
of
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import classNames from 'classnames/bind'
|
import { me } from '../initial_state'
|
||||||
|
import {
|
||||||
|
CX,
|
||||||
|
POPOVER_USER_INFO,
|
||||||
|
} from '../constants'
|
||||||
import { openPopover, closePopover } from '../actions/popover'
|
import { openPopover, closePopover } from '../actions/popover'
|
||||||
import Icon from './icon'
|
import Icon from './icon'
|
||||||
|
import Text from './text'
|
||||||
const cx = classNames.bind(_s)
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
openUserInfoPopover(props) {
|
openUserInfoPopover(props) {
|
||||||
dispatch(openPopover('USER_INFO', props))
|
dispatch(openPopover(POPOVER_USER_INFO, props))
|
||||||
},
|
},
|
||||||
closeUserInfoPopover() {
|
closeUserInfoPopover() {
|
||||||
dispatch(closePopover('USER_INFO'))
|
dispatch(closePopover(POPOVER_USER_INFO))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -23,13 +26,24 @@ class DisplayName extends ImmutablePureComponent {
|
|||||||
account: ImmutablePropTypes.map,
|
account: ImmutablePropTypes.map,
|
||||||
openUserInfoPopover: PropTypes.func.isRequired,
|
openUserInfoPopover: PropTypes.func.isRequired,
|
||||||
closeUserInfoPopover: PropTypes.func.isRequired,
|
closeUserInfoPopover: PropTypes.func.isRequired,
|
||||||
multiline: PropTypes.bool,
|
isLarge: PropTypes.bool,
|
||||||
small: PropTypes.bool,
|
isMultiline: PropTypes.bool,
|
||||||
large: PropTypes.bool,
|
isSmall: PropTypes.bool,
|
||||||
noHover: PropTypes.bool,
|
noHover: PropTypes.bool,
|
||||||
|
noRelationship: PropTypes.bool,
|
||||||
noUsername: PropTypes.bool,
|
noUsername: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateOnProps = [
|
||||||
|
'account',
|
||||||
|
'isMultiline',
|
||||||
|
'isSmall',
|
||||||
|
'isLarge',
|
||||||
|
'noHover',
|
||||||
|
'noRelationship',
|
||||||
|
'noUsername',
|
||||||
|
]
|
||||||
|
|
||||||
mouseOverTimeout = null
|
mouseOverTimeout = null
|
||||||
|
|
||||||
handleMouseEnter = () => {
|
handleMouseEnter = () => {
|
||||||
@ -58,41 +72,38 @@ class DisplayName extends ImmutablePureComponent {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
account,
|
account,
|
||||||
multiline,
|
isMultiline,
|
||||||
large,
|
isLarge,
|
||||||
noHover,
|
noHover,
|
||||||
noUsername,
|
noUsername,
|
||||||
small
|
noRelationship,
|
||||||
|
isSmall
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
if (!account) return null
|
if (!account) return null
|
||||||
|
|
||||||
const containerOptions = {
|
const containerClassName = CX({
|
||||||
className: cx({
|
default: 1,
|
||||||
default: 1,
|
maxWidth100PC: 1,
|
||||||
maxWidth100PC: 1,
|
alignItemsCenter: !isMultiline,
|
||||||
alignItemsCenter: !multiline,
|
flexRow: !isMultiline,
|
||||||
flexRow: !multiline,
|
cursorPointer: !noHover,
|
||||||
cursorPointer: !noHover,
|
})
|
||||||
}),
|
|
||||||
onMouseEnter: noHover ? undefined : this.handleMouseEnter,
|
|
||||||
onMouseLeave: noHover ? undefined : this.handleMouseLeave,
|
|
||||||
}
|
|
||||||
|
|
||||||
const displayNameClasses = cx({
|
const displayNameClasses = CX({
|
||||||
text: 1,
|
text: 1,
|
||||||
overflowWrapBreakWord: 1,
|
overflowWrapBreakWord: 1,
|
||||||
whiteSpaceNoWrap: 1,
|
whiteSpaceNoWrap: 1,
|
||||||
fontWeightBold: 1,
|
fontWeightBold: 1,
|
||||||
colorPrimary: 1,
|
colorPrimary: 1,
|
||||||
mr2: 1,
|
mr2: 1,
|
||||||
lineHeight125: !small,
|
lineHeight125: !isSmall,
|
||||||
fontSize14PX: small,
|
fontSize14PX: isSmall,
|
||||||
fontSize15PX: !large,
|
fontSize15PX: !isLarge,
|
||||||
fontSize24PX: large && !small,
|
fontSize24PX: isLarge && !isSmall,
|
||||||
})
|
})
|
||||||
|
|
||||||
const usernameClasses = cx({
|
const usernameClasses = CX({
|
||||||
text: 1,
|
text: 1,
|
||||||
displayFlex: 1,
|
displayFlex: 1,
|
||||||
flexNormal: 1,
|
flexNormal: 1,
|
||||||
@ -101,57 +112,83 @@ class DisplayName extends ImmutablePureComponent {
|
|||||||
textOverflowEllipsis: 1,
|
textOverflowEllipsis: 1,
|
||||||
colorSecondary: 1,
|
colorSecondary: 1,
|
||||||
fontWeightNormal: 1,
|
fontWeightNormal: 1,
|
||||||
lineHeight15: multiline,
|
lineHeight15: isMultiline,
|
||||||
lineHeight125: !multiline,
|
lineHeight125: !isMultiline,
|
||||||
ml5: !multiline,
|
ml5: !isMultiline,
|
||||||
fontSize14PX: small,
|
fontSize14PX: isSmall,
|
||||||
fontSize15PX: !large,
|
fontSize15PX: !isLarge,
|
||||||
fontSize16PX: large && !small,
|
fontSize16PX: isLarge && !isSmall,
|
||||||
})
|
})
|
||||||
|
|
||||||
const iconSize =
|
const iconSize =
|
||||||
!!large ? '19px' :
|
!!isLarge ? '19px' :
|
||||||
!!small ? '14px' : '16px'
|
!!isSmall ? '14px' : '16px'
|
||||||
|
|
||||||
const domain = account.get('acct').split('@')[1]
|
const domain = account.get('acct').split('@')[1]
|
||||||
const isRemoteUser = !!domain
|
const isRemoteUser = !!domain
|
||||||
|
|
||||||
|
let relationshipLabel
|
||||||
|
if (me && account) {
|
||||||
|
const accountId = account.get('id')
|
||||||
|
const isFollowedBy = (me !== accountId && account.getIn(['relationship', 'followed_by']))
|
||||||
|
|
||||||
|
if (isFollowedBy) {
|
||||||
|
relationshipLabel = 'Follows you'//intl.formatMessage(messages.accountFollowsYou)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// /* : todo : audio-mute
|
||||||
|
// account.getIn(['relationship', 'muting'])
|
||||||
|
// */
|
||||||
|
// }
|
||||||
|
|
||||||
// : todo : remote
|
// : todo : remote
|
||||||
console.log("domain, isRemoteUser:", domain, isRemoteUser)
|
console.log("domain, isRemoteUser:", domain, isRemoteUser)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span {...containerOptions} ref={this.setRef}>
|
<div
|
||||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
className={containerClassName}
|
||||||
|
onMouseEnter={noHover ? undefined : this.handleMouseEnter}
|
||||||
|
onMouseLeave={noHover ? undefined : this.handleMouseLeave}
|
||||||
|
ref={this.setRef}
|
||||||
|
>
|
||||||
|
<span className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
<bdi className={[_s.text, _s.whiteSpaceNoWrap, _s.textOverflowEllipsis].join(' ')}>
|
<bdi className={[_s.text, _s.whiteSpaceNoWrap, _s.textOverflowEllipsis].join(' ')}>
|
||||||
<strong
|
<strong
|
||||||
className={displayNameClasses}
|
className={displayNameClasses}
|
||||||
dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }}
|
dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }}
|
||||||
/>
|
/>
|
||||||
|
{
|
||||||
|
!noRelationship && account.get('locked') &&
|
||||||
|
<Icon id='lock-filled' size={iconSize} className={_s.ml5} />
|
||||||
|
}
|
||||||
</bdi>
|
</bdi>
|
||||||
{
|
{
|
||||||
account.get('is_verified') &&
|
account.get('is_verified') &&
|
||||||
<Icon id='verified' size={iconSize} className={_s.default} />
|
<Icon id='verified' size={iconSize} className={_s.default} />
|
||||||
}
|
}
|
||||||
{
|
</span>
|
||||||
account.get('is_pro') &&
|
|
||||||
<Icon id='pro' size={iconSize} className={_s.default} />
|
|
||||||
}
|
|
||||||
{
|
|
||||||
account.get('is_donor') &&
|
|
||||||
<Icon id='donor' size={iconSize} className={_s.default} />
|
|
||||||
}
|
|
||||||
{
|
|
||||||
account.get('is_investor') &&
|
|
||||||
<Icon id='investor' size={iconSize} className={_s.default} />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
{
|
{
|
||||||
!noUsername &&
|
!noUsername &&
|
||||||
<span className={usernameClasses}>
|
<span className={usernameClasses}>
|
||||||
@{account.get('acct')}
|
@{account.get('acct')}
|
||||||
|
{
|
||||||
|
!noRelationship && !!relationshipLabel &&
|
||||||
|
<span className={[_s.default, _s.ml5, _s.justifyContentCenter].join(' ')}>
|
||||||
|
<Text
|
||||||
|
size='extraSmall'
|
||||||
|
isBadge
|
||||||
|
color='tertiary'
|
||||||
|
className={[_s.backgroundSubtle2, _s.py2].join(' ')}
|
||||||
|
>
|
||||||
|
{relationshipLabel}
|
||||||
|
</Text>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
</span>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ class GroupHeader extends ImmutablePureComponent {
|
|||||||
<div className={[_s.default, _s.height53PX, _s.width100PC].join(' ')}>
|
<div className={[_s.default, _s.height53PX, _s.width100PC].join(' ')}>
|
||||||
<div className={[_s.default, _s.flexRow, _s.height100PC, _s.px10].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.height100PC, _s.px10].join(' ')}>
|
||||||
<TabBar tabs={tabs} />
|
<TabBar tabs={tabs} />
|
||||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.height100PC, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.height100PC, _s.mlAuto].join(' ')}>
|
||||||
<Button
|
<Button
|
||||||
color='primary'
|
color='primary'
|
||||||
backgroundColor='tertiary'
|
backgroundColor='tertiary'
|
||||||
|
@ -2,43 +2,33 @@ import { FormattedMessage } from 'react-intl'
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import { shortNumberFormat } from '../utils/numbers'
|
|
||||||
import Text from './text'
|
|
||||||
import Button from './button'
|
import Button from './button'
|
||||||
|
import Text from './text'
|
||||||
|
|
||||||
export default class HashtagItem extends ImmutablePureComponent {
|
export default class HashtagItem extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
hashtag: ImmutablePropTypes.map.isRequired,
|
hashtag: ImmutablePropTypes.map.isRequired,
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
hovering: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOnMouseEnter = () => {
|
updateOnProps = ['hashtag']
|
||||||
this.setState({ hovering: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOnMouseLeave = () => {
|
|
||||||
this.setState({ hovering: false })
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { hashtag } = this.props
|
const { hashtag } = this.props
|
||||||
const { hovering } = this.state
|
|
||||||
|
const count = hashtag.get('history').map((block) => {
|
||||||
|
return parseInt(block.get('uses'))
|
||||||
|
}).reduce((a, c) => a + c)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavLink
|
<NavLink
|
||||||
to='/tags/test'
|
to={`/tags/${hashtag.get('name')}`}
|
||||||
className={[_s.default, _s.noUnderline, _s.backgroundSubtle_onHover, _s.px15, _s.py5].join(' ')}
|
className={[_s.default, _s.noUnderline, _s.backgroundSubtle_onHover, _s.px15, _s.py5].join(' ')}
|
||||||
onMouseEnter={this.handleOnMouseEnter}
|
|
||||||
onMouseLeave={this.handleOnMouseLeave}
|
|
||||||
>
|
>
|
||||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
<div>
|
<div>
|
||||||
<Text color='brand' size='medium' weight='bold' className={[_s.py2, _s.lineHeight15].join(' ')}>
|
<Text color='brand' size='medium' weight='bold' className={[_s.py2, _s.lineHeight15].join(' ')}>
|
||||||
#randomhashtag
|
{hashtag.get('name')}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
@ -46,14 +36,16 @@ export default class HashtagItem extends ImmutablePureComponent {
|
|||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
color='none'
|
color='none'
|
||||||
title='Remove'
|
title='Remove'
|
||||||
icon='caret-down'
|
icon='close'
|
||||||
iconSize='8px'
|
iconSize='8px'
|
||||||
iconClassName={_s.fillColorSecondary}
|
iconClassName={_s.fillColorSecondary}
|
||||||
className={_s.marginLeftAuto}
|
className={_s.mlAuto}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Text color='secondary' size='small' className={_s.py2}>
|
<Text color='secondary' size='small' className={_s.py2}>
|
||||||
10,240 Gabs
|
<FormattedMessage id='number_of_gabs' defaultMessage='{count} Gabs' values={{
|
||||||
|
count,
|
||||||
|
}} />
|
||||||
</Text>
|
</Text>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)
|
)
|
||||||
|
@ -39,8 +39,8 @@ export default class Heading extends PureComponent {
|
|||||||
text: 1,
|
text: 1,
|
||||||
textAlignCenter: center,
|
textAlignCenter: center,
|
||||||
|
|
||||||
colorPrimary: [SIZES.h1, SIZES.h3].indexOf(size) > -1,
|
colorPrimary: [SIZES.h1, SIZES.h2].indexOf(size) > -1,
|
||||||
colorSecondary: [SIZES.h2, SIZES.h4, SIZES.h5].indexOf(size) > -1,
|
colorSecondary: [SIZES.h3, SIZES.h4, SIZES.h5].indexOf(size) > -1,
|
||||||
|
|
||||||
fontSize24PX: size === SIZES.h1,
|
fontSize24PX: size === SIZES.h1,
|
||||||
fontSize19PX: size === SIZES.h2,
|
fontSize19PX: size === SIZES.h2,
|
||||||
@ -48,13 +48,13 @@ export default class Heading extends PureComponent {
|
|||||||
fontSize13PX: size === SIZES.h4,
|
fontSize13PX: size === SIZES.h4,
|
||||||
fontSize12PX: size === SIZES.h5,
|
fontSize12PX: size === SIZES.h5,
|
||||||
|
|
||||||
mt5: [SIZES.h2, SIZES.h4].indexOf(size) > -1,
|
mt5: [SIZES.h4].indexOf(size) > -1,
|
||||||
|
|
||||||
lineHeight2: size === SIZES.h5,
|
lineHeight2: size === SIZES.h5,
|
||||||
py2: size === SIZES.h5,
|
py2: size === SIZES.h5,
|
||||||
|
|
||||||
fontWeightMedium: [SIZES.h1, SIZES.h5].indexOf(size) > -1,
|
fontWeightMedium: [SIZES.h1, SIZES.h3, SIZES.h5].indexOf(size) > -1,
|
||||||
fontWeightBold: [SIZES.h3, SIZES.h4].indexOf(size) > -1,
|
fontWeightBold: [SIZES.h2, SIZES.h4].indexOf(size) > -1,
|
||||||
})
|
})
|
||||||
|
|
||||||
return React.createElement(
|
return React.createElement(
|
||||||
|
@ -19,6 +19,7 @@ export default class Image extends PureComponent {
|
|||||||
fit: PropTypes.oneOf(['contain', 'cover', 'tile', 'none']),
|
fit: PropTypes.oneOf(['contain', 'cover', 'tile', 'none']),
|
||||||
nullable: PropTypes.bool,
|
nullable: PropTypes.bool,
|
||||||
lazy: PropTypes.bool,
|
lazy: PropTypes.bool,
|
||||||
|
ref: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@ -36,6 +37,7 @@ export default class Image extends PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
alt,
|
||||||
src,
|
src,
|
||||||
fit,
|
fit,
|
||||||
className,
|
className,
|
||||||
@ -64,6 +66,7 @@ export default class Image extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
|
alt={alt}
|
||||||
className={classes}
|
className={classes}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
src={src}
|
src={src}
|
||||||
|
@ -114,7 +114,7 @@ class LinkFooter extends PureComponent {
|
|||||||
onClick={linkFooterItem.onClick || null}
|
onClick={linkFooterItem.onClick || null}
|
||||||
className={[_s.my5, _s.pr15].join(' ')}
|
className={[_s.my5, _s.pr15].join(' ')}
|
||||||
>
|
>
|
||||||
<Text size='small' color='secondary'>
|
<Text size='small' color='tertiary'>
|
||||||
{linkFooterItem.text}
|
{linkFooterItem.text}
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
@ -123,11 +123,11 @@ class LinkFooter extends PureComponent {
|
|||||||
}
|
}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<Text size='small' color='secondary' className={_s.mt10}>
|
<Text size='small' color='tertiary' className={_s.mt10}>
|
||||||
© {currentYear} Gab AI, Inc.
|
© {currentYear} Gab AI, Inc.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text size='small' color='secondary' tagName='p' className={_s.mt10}>
|
<Text size='small' color='tertiary' tagName='p' className={_s.mt10}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='getting_started.open_source_notice'
|
id='getting_started.open_source_notice'
|
||||||
defaultMessage='Gab Social is open source software. You can contribute or report issues on our self-hosted GitLab at {gitlab}.'
|
defaultMessage='Gab Social is open source software. You can contribute or report issues on our self-hosted GitLab at {gitlab}.'
|
||||||
|
@ -86,7 +86,7 @@ export default class ListItem extends PureComponent {
|
|||||||
<Icon
|
<Icon
|
||||||
id='angle-right'
|
id='angle-right'
|
||||||
size='10px'
|
size='10px'
|
||||||
className={[_s.marginLeftAuto, _s.fillColorBlack].join(' ')}
|
className={[_s.mlAuto, _s.fillColorSecondary].join(' ')}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -46,7 +46,7 @@ class LoadMore extends PureComponent {
|
|||||||
>
|
>
|
||||||
{
|
{
|
||||||
!gap &&
|
!gap &&
|
||||||
<Text color='inherit'>
|
<Text color='inherit' align='center'>
|
||||||
{intl.formatMessage(messages.load_more)}
|
{intl.formatMessage(messages.load_more)}
|
||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,86 @@
|
|||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import Button from '../button'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import Text from '../text'
|
import { me } from '../../initial_state'
|
||||||
import ModalLayout from './modal_layout'
|
import ModalLayout from './modal_layout'
|
||||||
|
import Avatar from '../avatar'
|
||||||
|
import Button from '../button'
|
||||||
|
import Divider from '../divider'
|
||||||
|
import Image from '../image'
|
||||||
|
import Input from '../input'
|
||||||
|
import Text from '../text'
|
||||||
|
import Textarea from '../textarea'
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||||
|
headerPhoto: { id: 'header_photo', defaultMessage: 'Header photo' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
account: state.getIn(['accounts', me]),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@injectIntl
|
@injectIntl
|
||||||
|
@connect(mapStateToProps)
|
||||||
class EditProfileModal extends ImmutablePureComponent {
|
class EditProfileModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
account: ImmutablePropTypes.map,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { intl } = this.props
|
const { account, intl } = this.props
|
||||||
|
|
||||||
|
const headerSrc = !!account ? account.get('header') : ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalLayout>
|
<ModalLayout
|
||||||
test
|
title={intl.formatMessage(messages.edit_profile)}
|
||||||
|
noPadding
|
||||||
|
width={460}
|
||||||
|
>
|
||||||
|
<div className={[_s.default, _s.py5, _s.px5, _s.width100PC, _s.overflowHidden].join(' ')}>
|
||||||
|
<Image
|
||||||
|
alt={intl.formatMessage(messages.headerPhoto)}
|
||||||
|
className={_s.radiusSmall}
|
||||||
|
height='180px'
|
||||||
|
src={headerSrc}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.pl25].join(' ')}>
|
||||||
|
<div className={[_s.default, _s.circle, _s.mtNeg75PX, _s.boxShadowProfileAvatar].join(' ')}>
|
||||||
|
<Avatar
|
||||||
|
size={98}
|
||||||
|
account={account}
|
||||||
|
noHover
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={[_s.default, _s.px15, _s.py15].join(' ')}>
|
||||||
|
<Input
|
||||||
|
title='Name'
|
||||||
|
value=''
|
||||||
|
disabled={false}
|
||||||
|
// onChange={this.handleTitleChange}
|
||||||
|
placeholder='Add your name...'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider isInvisible />
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
title='Bio'
|
||||||
|
value=''
|
||||||
|
disabled={false}
|
||||||
|
// onChange={this.handleDescriptionChange}
|
||||||
|
placeholder='Add your bio...'
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</ModalLayout>
|
</ModalLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ class GifPickerModal extends PureComponent {
|
|||||||
<Button
|
<Button
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
title={intl.formatMessage(messages.close)}
|
title={intl.formatMessage(messages.close)}
|
||||||
className={_s.marginLeftAuto}
|
className={_s.mlAuto}
|
||||||
onClick={this.onHandleCloseModal}
|
onClick={this.onHandleCloseModal}
|
||||||
color='secondary'
|
color='secondary'
|
||||||
icon='close'
|
icon='close'
|
||||||
|
@ -53,7 +53,7 @@ class ModalLayout extends PureComponent {
|
|||||||
<div style={{width: `${width}px`}}>
|
<div style={{width: `${width}px`}}>
|
||||||
<Block>
|
<Block>
|
||||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.height53PX, _s.px15].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.height53PX, _s.px15].join(' ')}>
|
||||||
<Heading size='h3'>
|
<Heading size='h2'>
|
||||||
{title}
|
{title}
|
||||||
</Heading>
|
</Heading>
|
||||||
{
|
{
|
||||||
@ -61,7 +61,7 @@ class ModalLayout extends PureComponent {
|
|||||||
<Button
|
<Button
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
title={intl.formatMessage(messages.close)}
|
title={intl.formatMessage(messages.close)}
|
||||||
className={_s.marginLeftAuto}
|
className={_s.mlAuto}
|
||||||
onClick={this.onHandleCloseModal}
|
onClick={this.onHandleCloseModal}
|
||||||
color='secondary'
|
color='secondary'
|
||||||
icon='close'
|
icon='close'
|
||||||
|
@ -34,7 +34,7 @@ class UnauthorizedModal extends ImmutablePureComponent {
|
|||||||
<Text className={_s.mb15}>
|
<Text className={_s.mb15}>
|
||||||
{intl.formatMessage(messages.text)}
|
{intl.formatMessage(messages.text)}
|
||||||
</Text>
|
</Text>
|
||||||
<Button href='/auth/sign_up' className={[_s.width240PX, _s.marginLeftAuto, _s.marginLeftAuto].join(' ')}>
|
<Button href='/auth/sign_up' className={[_s.width240PX, _s.mlAuto, _s.mlAuto].join(' ')}>
|
||||||
{intl.formatMessage(messages.register)}
|
{intl.formatMessage(messages.register)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,11 +3,11 @@ import { injectIntl, defineMessages } from 'react-intl'
|
|||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { HotKeys } from 'react-hotkeys'
|
import { HotKeys } from 'react-hotkeys'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import StatusContainer from '../../../containers/status_container'
|
import StatusContainer from '../containers/status_container'
|
||||||
import Avatar from '../../../components/avatar'
|
import Avatar from './avatar'
|
||||||
import Icon from '../../../components/icon'
|
import Icon from './icon'
|
||||||
import Text from '../../../components/text'
|
import Text from './text'
|
||||||
import DisplayName from '../../../components/display_name'
|
import DisplayName from './display_name'
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
poll: { id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' },
|
poll: { id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' },
|
@ -33,7 +33,7 @@ class GroupInfoPanel extends ImmutablePureComponent {
|
|||||||
!!group &&
|
!!group &&
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|
||||||
<Heading size='h3'>
|
<Heading size='h2'>
|
||||||
{group.get('title')}
|
{group.get('title')}
|
||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class GroupInfoPanel extends ImmutablePureComponent {
|
|||||||
to={`/groups/${group.get('id')}/members`}
|
to={`/groups/${group.get('id')}/members`}
|
||||||
color='brand'
|
color='brand'
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
className={_s.marginLeftAuto}
|
className={_s.mlAuto}
|
||||||
>
|
>
|
||||||
<Text color='inherit' weight='medium' size='normal' className={_s.underline_onHover}>
|
<Text color='inherit' weight='medium' size='normal' className={_s.underline_onHover}>
|
||||||
{shortNumberFormat(group.get('member_count'))}
|
{shortNumberFormat(group.get('member_count'))}
|
||||||
|
@ -4,7 +4,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import PanelLayout from './panel_layout'
|
import PanelLayout from './panel_layout'
|
||||||
import HashtagItem from '../hashtag_item'
|
import HashtagItem from '../hashtag_item'
|
||||||
import Button from '../button'
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'hashtags.title', defaultMessage: 'Popular Hashtags' },
|
title: { id: 'hashtags.title', defaultMessage: 'Popular Hashtags' },
|
||||||
@ -30,6 +29,10 @@ class HashtagsPanel extends ImmutablePureComponent {
|
|||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateOnProps = [
|
||||||
|
'hashtags',
|
||||||
|
]
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchHashtags()
|
this.props.fetchHashtags()
|
||||||
}
|
}
|
||||||
@ -37,27 +40,23 @@ class HashtagsPanel extends ImmutablePureComponent {
|
|||||||
render() {
|
render() {
|
||||||
const { intl, hashtags } = this.props
|
const { intl, hashtags } = this.props
|
||||||
|
|
||||||
// !!! TESTING !!!
|
if (hashtags.isEmpty()) {
|
||||||
// if (hashtags.isEmpty()) {
|
return null
|
||||||
// return null
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelLayout
|
<PanelLayout
|
||||||
noPadding
|
noPadding
|
||||||
title={intl.formatMessage(messages.title)}
|
title={intl.formatMessage(messages.title)}
|
||||||
footerButtonTitle={intl.formatMessage(messages.show_all)}
|
footerButtonTitle={intl.formatMessage(messages.show_all)}
|
||||||
footerButtonTo='/explore'
|
footerButtonTo='/search'
|
||||||
>
|
>
|
||||||
<div className={_s.default}>
|
<div className={_s.default}>
|
||||||
{ /* hashtags && hashtags.map(hashtag => (
|
{
|
||||||
<HashtagingItem key={hashtag.get('name')} hashtag={hashtag} />
|
hashtags.map(hashtag => (
|
||||||
)) */ }
|
<HashtagItem key={hashtag.get('name')} hashtag={hashtag} />
|
||||||
<HashtagItem />
|
))
|
||||||
<HashtagItem />
|
}
|
||||||
<HashtagItem />
|
|
||||||
<HashtagItem />
|
|
||||||
<HashtagItem />
|
|
||||||
</div>
|
</div>
|
||||||
</PanelLayout>
|
</PanelLayout>
|
||||||
)
|
)
|
||||||
|
@ -58,9 +58,8 @@ class ListsPanel extends ImmutablePureComponent {
|
|||||||
footerButtonTo={count > maxCount ? '/lists' : undefined}
|
footerButtonTo={count > maxCount ? '/lists' : undefined}
|
||||||
noPadding
|
noPadding
|
||||||
>
|
>
|
||||||
<div className={_s.default}>
|
<div className={[_s.default, _s.boxShadowNone].join(' ')}>
|
||||||
<List
|
<List
|
||||||
unrounded
|
|
||||||
scrollKey='lists_sidebar_panel'
|
scrollKey='lists_sidebar_panel'
|
||||||
items={listItems}
|
items={listItems}
|
||||||
/>
|
/>
|
||||||
|
@ -36,14 +36,14 @@ export default class PanelLayout extends PureComponent {
|
|||||||
<Block>
|
<Block>
|
||||||
{
|
{
|
||||||
(title || subtitle) &&
|
(title || subtitle) &&
|
||||||
<div className={[_s.default, _s.px15, _s.py10, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}>
|
<div className={[_s.default, _s.px15, _s.py10].join(' ')}>
|
||||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
<Heading size='h3'>
|
<Heading size='h2'>
|
||||||
{title}
|
{title}
|
||||||
</Heading>
|
</Heading>
|
||||||
{
|
{
|
||||||
(!!headerButtonTitle && (!!headerButtonAction || !!headerButtonTo)) &&
|
(!!headerButtonTitle && (!!headerButtonAction || !!headerButtonTo)) &&
|
||||||
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.mlAuto].join(' ')}>
|
||||||
<Button
|
<Button
|
||||||
isText
|
isText
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
@ -80,7 +80,7 @@ export default class PanelLayout extends PureComponent {
|
|||||||
|
|
||||||
{
|
{
|
||||||
(!!footerButtonTitle && (!!footerButtonAction || !!footerButtonTo)) &&
|
(!!footerButtonTitle && (!!footerButtonAction || !!footerButtonTo)) &&
|
||||||
<div className={[_s.default, _s.borderColorSecondary, _s.borderTop1PX].join(' ')}>
|
<div className={_s.default}>
|
||||||
<Button
|
<Button
|
||||||
isText
|
isText
|
||||||
color='none'
|
color='none'
|
||||||
|
@ -54,6 +54,10 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
|||||||
const content = { __html: account.get('note_emojified') }
|
const content = { __html: account.get('note_emojified') }
|
||||||
const memberSinceDate = intl.formatDate(account.get('created_at'), { month: 'long', year: 'numeric' })
|
const memberSinceDate = intl.formatDate(account.get('created_at'), { month: 'long', year: 'numeric' })
|
||||||
const hasNote = !!content ? (account.get('note').length > 0 && account.get('note') !== '<p></p>') : false
|
const hasNote = !!content ? (account.get('note').length > 0 && account.get('note') !== '<p></p>') : false
|
||||||
|
const isPro = account.get('is_pro')
|
||||||
|
const isDonor = account.get('is_donor')
|
||||||
|
const isInvestor = account.get('is_investor')
|
||||||
|
const hasBadges = isPro || isDonor || isInvestor
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelLayout title={intl.formatMessage(messages.title)}>
|
<PanelLayout title={intl.formatMessage(messages.title)}>
|
||||||
@ -81,6 +85,18 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
|||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
hasBadges &&
|
||||||
|
<Fragment>
|
||||||
|
<Divider isSmall />
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
|
{ isPro && <Icon id='pro' size='16px' className={_s.mr5} /> }
|
||||||
|
{ isInvestor && <Icon id='investor' size='16px' className={_s.mr5} /> }
|
||||||
|
{ isDonor && <Icon id='donor' size='16px' /> }
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
|
||||||
{(fields.size > 0 || identityProofs.size > 0) && (
|
{(fields.size > 0 || identityProofs.size > 0) && (
|
||||||
<div className={[_s.default]}>
|
<div className={[_s.default]}>
|
||||||
{identityProofs.map((proof, i) => (
|
{identityProofs.map((proof, i) => (
|
||||||
@ -121,7 +137,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
|||||||
title={pair.get('name')}
|
title={pair.get('name')}
|
||||||
/>
|
/>
|
||||||
<dd
|
<dd
|
||||||
className={[_s.dangerousContent, _s.marginLeftAuto].join(' ')}
|
className={[_s.dangerousContent, _s.mlAuto].join(' ')}
|
||||||
title={pair.get('value_plain')}
|
title={pair.get('value_plain')}
|
||||||
dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }}
|
dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }}
|
||||||
/>
|
/>
|
||||||
|
@ -106,11 +106,11 @@ class UserPanel extends ImmutablePureComponent {
|
|||||||
className={[_s.default, _s.flexRow, _s.py10, _s.px15, _s.noUnderline].join(' ')}
|
className={[_s.default, _s.flexRow, _s.py10, _s.px15, _s.noUnderline].join(' ')}
|
||||||
to={`/${acct}`}
|
to={`/${acct}`}
|
||||||
>
|
>
|
||||||
<div className={[_s.default, _s.mtNeg30PX, _s.circle, _s.borderColorWhite, _s.border2PX].join(' ')}>
|
<div className={[_s.default, _s.mtNeg32PX, _s.circle, _s.borderColorWhite, _s.border6PX].join(' ')}>
|
||||||
<Avatar account={account} size={62} />
|
<Avatar account={account} size={62} noHover />
|
||||||
</div>
|
</div>
|
||||||
<div className={[_s.default, _s.ml15].join(' ')}>
|
<div className={[_s.default, _s.ml15].join(' ')}>
|
||||||
<DisplayName account={account} multiline />
|
<DisplayName account={account} isMultiline noRelationship noHover />
|
||||||
</div>
|
</div>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ class Poll extends ImmutablePureComponent {
|
|||||||
|
|
||||||
{
|
{
|
||||||
showResults &&
|
showResults &&
|
||||||
<span className={_s.marginLeftAuto}>
|
<span className={_s.mlAuto}>
|
||||||
{Math.round(percent)}%
|
{Math.round(percent)}%
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import DatePickerPopover from './date_picker_popover'
|
|||||||
import EmojiPickerPopover from './emoji_picker_popover'
|
import EmojiPickerPopover from './emoji_picker_popover'
|
||||||
import GroupInfoPopover from './group_info_popover'
|
import GroupInfoPopover from './group_info_popover'
|
||||||
import ProfileOptionsPopover from './profile_options_popover'
|
import ProfileOptionsPopover from './profile_options_popover'
|
||||||
|
import RepostOptionsPopover from './repost_options_popover'
|
||||||
import SearchPopover from './search_popover'
|
import SearchPopover from './search_popover'
|
||||||
import SidebarMorePopover from './sidebar_more_popover'
|
import SidebarMorePopover from './sidebar_more_popover'
|
||||||
import StatusOptionsPopover from './status_options_popover'
|
import StatusOptionsPopover from './status_options_popover'
|
||||||
@ -23,6 +24,7 @@ const POPOVER_COMPONENTS = {
|
|||||||
EMOJI_PICKER: () => Promise.resolve({ default: EmojiPickerPopover }),
|
EMOJI_PICKER: () => Promise.resolve({ default: EmojiPickerPopover }),
|
||||||
GROUP_INFO: () => GroupInfoPopover,
|
GROUP_INFO: () => GroupInfoPopover,
|
||||||
PROFILE_OPTIONS: () => Promise.resolve({ default: ProfileOptionsPopover }),
|
PROFILE_OPTIONS: () => Promise.resolve({ default: ProfileOptionsPopover }),
|
||||||
|
REPOST_OPTIONS: () => Promise.resolve({ default: RepostOptionsPopover }),
|
||||||
SEARCH: () => Promise.resolve({ default: SearchPopover }),
|
SEARCH: () => Promise.resolve({ default: SearchPopover }),
|
||||||
SIDEBAR_MORE: () => Promise.resolve({ default: SidebarMorePopover }),
|
SIDEBAR_MORE: () => Promise.resolve({ default: SidebarMorePopover }),
|
||||||
STATUS_OPTIONS: () => Promise.resolve({ default: StatusOptionsPopover }),
|
STATUS_OPTIONS: () => Promise.resolve({ default: StatusOptionsPopover }),
|
||||||
|
@ -50,7 +50,6 @@ const messages = defineMessages({
|
|||||||
admin_account: { id: 'admin_account', defaultMessage: 'Open moderation interface' },
|
admin_account: { id: 'admin_account', defaultMessage: 'Open moderation interface' },
|
||||||
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
||||||
add_or_remove_from_shortcuts: { id: 'account.add_or_remove_from_shortcuts', defaultMessage: 'Add or Remove from shortcuts' },
|
add_or_remove_from_shortcuts: { id: 'account.add_or_remove_from_shortcuts', defaultMessage: 'Add or Remove from shortcuts' },
|
||||||
accountFollowsYou: { id: 'account.follows_you', defaultMessage: 'Follows you' },
|
|
||||||
accountBlocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
|
accountBlocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
|
||||||
accountMuted: { id: 'account.muted', defaultMessage: 'Muted' },
|
accountMuted: { id: 'account.muted', defaultMessage: 'Muted' },
|
||||||
domainBlocked: { id: 'account.domain_blocked', defaultMessage: 'Domain hidden' },
|
domainBlocked: { id: 'account.domain_blocked', defaultMessage: 'Domain hidden' },
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import { quoteCompose } from '../../actions/compose'
|
||||||
|
import { repost, unrepost } from '../../actions/interactions'
|
||||||
|
import { openModal } from '../../actions/modal'
|
||||||
|
import { boostModal, me } from '../../initial_state'
|
||||||
|
import PopoverLayout from './popover_layout'
|
||||||
|
import List from '../list'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
repost: { id: 'repost', defaultMessage: 'Repost' },
|
||||||
|
repostWithComment: { id: 'repost_with_comment', defaultMessage: 'Repost with comment' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
|
onQuote (status, router) {
|
||||||
|
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
||||||
|
|
||||||
|
dispatch((_, getState) => {
|
||||||
|
const state = getState();
|
||||||
|
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||||
|
dispatch(openModal('CONFIRM', {
|
||||||
|
message: intl.formatMessage(messages.quoteMessage),
|
||||||
|
confirm: intl.formatMessage(messages.quoteConfirm),
|
||||||
|
onConfirm: () => dispatch(quoteCompose(status, router)),
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
dispatch(quoteCompose(status, router));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onRepost (status) {
|
||||||
|
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
||||||
|
|
||||||
|
if (status.get('reblogged')) {
|
||||||
|
dispatch(unrepost(status));
|
||||||
|
} else {
|
||||||
|
dispatch(repost(status));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default
|
||||||
|
@injectIntl
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
class RepostOptionsPopover extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
|
onQuote: PropTypes.func.isRequired,
|
||||||
|
onRepost: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOnProps = ['status']
|
||||||
|
|
||||||
|
handleOnRepost = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOnQuote = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { intl } = this.props
|
||||||
|
|
||||||
|
const listItems = [
|
||||||
|
{
|
||||||
|
hideArrow: true,
|
||||||
|
icon: 'repost',
|
||||||
|
title: intl.formatMessage(messages.repost),
|
||||||
|
onClick: this.handleOnRepost,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hideArrow: true,
|
||||||
|
icon: 'pencil',
|
||||||
|
title: intl.formatMessage(messages.repostWithComment),
|
||||||
|
onClick: this.handleBlockDomain,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopoverLayout width={220}>
|
||||||
|
<List
|
||||||
|
scrollKey='repost_options'
|
||||||
|
items={listItems}
|
||||||
|
size='large'
|
||||||
|
/>
|
||||||
|
</PopoverLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -28,11 +28,11 @@ export default class UserInfoPopover extends ImmutablePureComponent {
|
|||||||
to={to}
|
to={to}
|
||||||
className={[_s.default, _s.noUnderline, _s.flexGrow1].join(' ')}
|
className={[_s.default, _s.noUnderline, _s.flexGrow1].join(' ')}
|
||||||
>
|
>
|
||||||
<Avatar account={account} size={42} />
|
<Avatar account={account} size={42} noHover />
|
||||||
<DisplayName account={account} multiline noHover />
|
<DisplayName account={account} isMultiline noHover />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.mlAuto, _s.right0, _s.posAbs, _s.mt5].join(' ')}>
|
||||||
<AccountActionButton account={account} />
|
<AccountActionButton account={account} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,32 +2,37 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
|
|||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import Sticky from 'react-stickynode'
|
import Sticky from 'react-stickynode'
|
||||||
import classNames from 'classnames/bind'
|
import {
|
||||||
|
CX,
|
||||||
|
POPOVER_PROFILE_OPTIONS,
|
||||||
|
PLACEHOLDER_MISSING_HEADER_SRC,
|
||||||
|
} from '../constants'
|
||||||
import { openPopover } from '../actions/popover'
|
import { openPopover } from '../actions/popover'
|
||||||
import { me } from '../initial_state'
|
import { me } from '../initial_state'
|
||||||
import AccountActionButton from './account_action_button'
|
import AccountActionButton from './account_action_button'
|
||||||
import Avatar from './avatar'
|
import Avatar from './avatar'
|
||||||
import Button from './button'
|
import Button from './button'
|
||||||
import DisplayName from './display_name'
|
import DisplayName from './display_name'
|
||||||
import Icon from './icon'
|
|
||||||
import Image from './image'
|
import Image from './image'
|
||||||
import MovedNote from './moved_note'
|
import MovedNote from './moved_note'
|
||||||
import TabBar from './tab_bar'
|
import TabBar from './tab_bar'
|
||||||
import Text from './text'
|
import Text from './text'
|
||||||
|
|
||||||
const cx = classNames.bind(_s)
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
||||||
follows: { id: 'account.follows', defaultMessage: 'Follows' },
|
follows: { id: 'account.follows', defaultMessage: 'Follows' },
|
||||||
profile: { id: 'account.profile', defaultMessage: 'Profile' },
|
profile: { id: 'account.profile', defaultMessage: 'Profile' },
|
||||||
headerPhoto: { id: 'header_photo', defaultMessage: 'Header photo' },
|
headerPhoto: { id: 'header_photo', defaultMessage: 'Header photo' },
|
||||||
|
timeline: { id: 'timeline', defaultMessage: 'Timeline' },
|
||||||
|
comments: { id: 'comments', defaultMessage: 'Comments' },
|
||||||
|
media: { id: 'media', defaultMessage: 'Media' },
|
||||||
|
accountFollowsYou: { id: 'account.follows_you', defaultMessage: 'Follows you' },
|
||||||
})
|
})
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
|
||||||
openProfileOptionsPopover(props) {
|
openProfileOptionsPopover(props) {
|
||||||
dispatch(openPopover('PROFILE_OPTIONS', props))
|
dispatch(openPopover(POPOVER_PROFILE_OPTIONS, props))
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -49,44 +54,19 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
|
|
||||||
handleOpenMore = () => {
|
handleOpenMore = () => {
|
||||||
const { openProfileOptionsPopover, account } = this.props
|
const { openProfileOptionsPopover, account } = this.props
|
||||||
|
|
||||||
openProfileOptionsPopover({
|
openProfileOptionsPopover({
|
||||||
|
account,
|
||||||
targetRef: this.openMoreNode,
|
targetRef: this.openMoreNode,
|
||||||
position: 'top',
|
position: 'top',
|
||||||
account: this.props.account,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// : todo :
|
|
||||||
makeInfo = () => {
|
|
||||||
const { account, intl } = this.props
|
|
||||||
|
|
||||||
const info = []
|
|
||||||
|
|
||||||
if (!account || !me) return info;
|
|
||||||
|
|
||||||
if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
|
|
||||||
info.push(<span key='followed_by' className='relationship-tag'>{intl.formatMessage(messages.accountFollowsYou)}</span>);
|
|
||||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {
|
|
||||||
info.push(<span key='blocked' className='relationship-tag'>{intl.formatMessage(messages.accountBlocked)}</span>);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (me !== account.get('id') && account.getIn(['relationship', 'muting'])) {
|
|
||||||
info.push(<span key='muted' className='relationship-tag'>{intl.formatMessage(messages.accountMuted)}</span>);
|
|
||||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) {
|
|
||||||
info.push(<span key='domain_blocked' className='relationship-tag'>{intl.formatMessage(messages.domainBlocked)}</span>);
|
|
||||||
}
|
|
||||||
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
onStickyStateChange = (status) => {
|
onStickyStateChange = (status) => {
|
||||||
switch (status.status) {
|
if (status.status === Sticky.STATUS_FIXED) {
|
||||||
case Sticky.STATUS_FIXED:
|
this.setState({ stickied: true })
|
||||||
this.setState({ stickied: true })
|
} else {
|
||||||
break;
|
this.setState({ stickied: false })
|
||||||
default:
|
|
||||||
this.setState({ stickied: false })
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,34 +81,30 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
const tabs = !account ? null : [
|
const tabs = !account ? null : [
|
||||||
{
|
{
|
||||||
to: `/${account.get('acct')}`,
|
to: `/${account.get('acct')}`,
|
||||||
title: 'Timeline',
|
title: intl.formatMessage(messages.timeline),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
to: `/${account.get('acct')}/comments`,
|
to: `/${account.get('acct')}/comments`,
|
||||||
title: 'Comments',
|
title: intl.formatMessage(messages.comments),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
to: `/${account.get('acct')}/media`,
|
to: `/${account.get('acct')}/media`,
|
||||||
title: 'Media',
|
title: intl.formatMessage(messages.media),
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '',
|
|
||||||
title: 'More',
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const headerSrc = !!account ? account.get('header') : ''
|
const headerSrc = !!account ? account.get('header') : ''
|
||||||
const headerMissing = headerSrc.indexOf('/headers/original/missing.png') > -1 || !headerSrc
|
const headerMissing = headerSrc.indexOf(PLACEHOLDER_MISSING_HEADER_SRC) > -1 || !headerSrc
|
||||||
const avatarSize = headerMissing ? 75 : 150
|
const avatarSize = headerMissing ? 75 : 150
|
||||||
|
|
||||||
const avatarContainerClasses = cx({
|
const avatarContainerClasses = CX({
|
||||||
|
default: 1,
|
||||||
circle: 1,
|
circle: 1,
|
||||||
mtNeg75PX: !headerMissing,
|
mtNeg75PX: !headerMissing,
|
||||||
borderColorWhite: 1,
|
boxShadowProfileAvatar: !headerMissing,
|
||||||
border2PX: 1,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const stickyBarContainerClasses = cx({
|
const stickyBarContainerClasses = CX({
|
||||||
default: 1,
|
default: 1,
|
||||||
flexRow: 1,
|
flexRow: 1,
|
||||||
px15: 1,
|
px15: 1,
|
||||||
@ -136,14 +112,11 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
displayNone: !stickied,
|
displayNone: !stickied,
|
||||||
})
|
})
|
||||||
|
|
||||||
const tabBarContainerClasses = cx({
|
const tabBarContainerClasses = CX({
|
||||||
default: 1,
|
default: 1,
|
||||||
displayNone: stickied,
|
displayNone: stickied,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// : todo : "follows you", "mutual follow"
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.z1, _s.width100PC].join(' ')}>
|
<div className={[_s.default, _s.z1, _s.width100PC].join(' ')}>
|
||||||
|
|
||||||
@ -160,22 +133,13 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
|
|
||||||
<div className={[_s.default, _s.borderBottom1PX, _s.borderColorSecondary, _s.width100PC].join(' ')}>
|
<div className={[_s.default, _s.borderBottom1PX, _s.borderColorSecondary, _s.width100PC].join(' ')}>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexRow, _s.px15, _s.mb5].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.pr15, _s.pl25, _s.mb5].join(' ')}>
|
||||||
<div className={avatarContainerClasses}>
|
<div className={avatarContainerClasses}>
|
||||||
<Avatar size={avatarSize} account={account} />
|
<Avatar size={avatarSize} account={account} noHover />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={[_s.default, _s.flexRow, _s.px15, _s.py10].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.px15, _s.flexNormal, _s.py10].join(' ')}>
|
||||||
<DisplayName account={account} multiline large />
|
<DisplayName account={account} isMultiline noRelationship isLarge noHover />
|
||||||
{
|
|
||||||
account && account.get('locked') &&
|
|
||||||
<Icon id='lock-filled' size='14px' className={[_s.mt10, _s.ml10].join(' ')} />
|
|
||||||
}
|
|
||||||
{
|
|
||||||
/* : todo :
|
|
||||||
account.getIn(['relationship', 'muting'])
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -186,15 +150,15 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={stickyBarContainerClasses}>
|
<div className={stickyBarContainerClasses}>
|
||||||
<Avatar size={36} account={account} />
|
<Avatar size={36} account={account} noHover />
|
||||||
<div className={[_s.default, _s.ml10].join(' ')}>
|
<div className={[_s.default, _s.ml10].join(' ')}>
|
||||||
<DisplayName account={account} noUsername large />
|
<DisplayName account={account} noUsername noRelationship noHover isLarge />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
account && account.get('id') === me &&
|
account && account.get('id') === me &&
|
||||||
<div className={[_s.default, _s.flexRow, _s.marginLeftAuto, _s.py5].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.mlAuto, _s.py5].join(' ')}>
|
||||||
<Button
|
<Button
|
||||||
isOutline
|
isOutline
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
@ -216,19 +180,18 @@ class ProfileHeader extends ImmutablePureComponent {
|
|||||||
|
|
||||||
{
|
{
|
||||||
account && account.get('id') !== me &&
|
account && account.get('id') !== me &&
|
||||||
<div className={[_s.default, _s.flexRow, _s.marginLeftAuto, _s.py5].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.mlAuto, _s.py5].join(' ')}>
|
||||||
<div ref={this.setOpenMoreNodeRef}>
|
<Button
|
||||||
<Button
|
isOutline
|
||||||
isOutline
|
icon='ellipsis'
|
||||||
icon='ellipsis'
|
iconSize='18px'
|
||||||
iconSize='18px'
|
iconClassName={_s.inheritFill}
|
||||||
iconClassName={_s.inheritFill}
|
color='brand'
|
||||||
color='brand'
|
backgroundColor='none'
|
||||||
backgroundColor='none'
|
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
onClick={this.handleOpenMore}
|
||||||
onClick={this.handleOpenMore}
|
buttonRef={this.setOpenMoreNodeRef}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<form action='https://chat.gab.com/private-message' method='POST'>
|
<form action='https://chat.gab.com/private-message' method='POST'>
|
||||||
<Button
|
<Button
|
||||||
|
@ -42,11 +42,11 @@ export default class ProgressBar extends PureComponent {
|
|||||||
noClasses
|
noClasses
|
||||||
className={containerClassName}
|
className={containerClassName}
|
||||||
>
|
>
|
||||||
<div className={[_s.default, _s.backgroundColorBrandDark, _s.circle, _s.height100PC].join(' ')} style={style} />
|
<div className={[_s.default, _s.backgroundColorBrand, _s.circle, _s.height100PC, _s.backgroundCandy].join(' ')} style={style} />
|
||||||
<div className={[_s.default, _s.posAbs, _s.width100PC, _s.height100PC, _s.alignItemsCenter, _s.justifyContentCenter].join(' ')}>
|
<div className={[_s.default, _s.posAbs, _s.width100PC, _s.height100PC, _s.alignItemsCenter, _s.justifyContentCenter].join(' ')}>
|
||||||
{
|
{
|
||||||
!!title &&
|
!!title &&
|
||||||
<Text size='small' weight='bold' color='white'>
|
<Text size='small' weight='bold' color='white' className={_s.textShadow}>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ class RichTextEditorBar extends PureComponent {
|
|||||||
color='secondary'
|
color='secondary'
|
||||||
onClick={this.handleOnTogglePopoutEditor}
|
onClick={this.handleOnTogglePopoutEditor}
|
||||||
title='Fullscreen'
|
title='Fullscreen'
|
||||||
className={[_s.px10, _s.noSelect, _s.marginLeftAuto].join(' ')}
|
className={[_s.px10, _s.noSelect, _s.mlAuto].join(' ')}
|
||||||
icon='fullscreen'
|
icon='fullscreen'
|
||||||
iconClassName={_s.inheritFill}
|
iconClassName={_s.inheritFill}
|
||||||
iconSize='12px'
|
iconSize='12px'
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { withRouter } from 'react-router-dom'
|
||||||
|
import queryString from 'query-string'
|
||||||
import {
|
import {
|
||||||
changeSearch,
|
changeSearch,
|
||||||
clearSearch,
|
clearSearch,
|
||||||
@ -19,6 +21,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export default
|
export default
|
||||||
|
@withRouter
|
||||||
@connect(mapStateToProps, mapDispatchToProps)
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
class Search extends PureComponent {
|
class Search extends PureComponent {
|
||||||
|
|
||||||
@ -42,6 +45,18 @@ class Search extends PureComponent {
|
|||||||
|
|
||||||
textbox = React.createRef()
|
textbox = React.createRef()
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
// If user navigates to different page, ensure tab bar item
|
||||||
|
// with this.props.to that is on location is set to active.
|
||||||
|
if (this.props.location !== prevProps.location) {
|
||||||
|
const isCurrent = this.props.to === this.props.location.pathname
|
||||||
|
|
||||||
|
if (this.state.isCurrent !== isCurrent) {
|
||||||
|
this.setState({ isCurrent })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleChange = (e) => {
|
handleChange = (e) => {
|
||||||
this.props.onChange(e.target.value)
|
this.props.onChange(e.target.value)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ class SensitiveMediaItem extends PureComponent {
|
|||||||
{intl.formatMessage(messages.warning)}
|
{intl.formatMessage(messages.warning)}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={[_s.default, _s.justifyContentCenter, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.justifyContentCenter, _s.mlAuto].join(' ')}>
|
||||||
<Button
|
<Button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
color='tertiary'
|
color='tertiary'
|
||||||
|
@ -65,7 +65,6 @@ export default class SidebarSectionItem extends PureComponent {
|
|||||||
px10: 1,
|
px10: 1,
|
||||||
alignItemsCenter: 1,
|
alignItemsCenter: 1,
|
||||||
radiusSmall: 1,
|
radiusSmall: 1,
|
||||||
mt2: 1,
|
|
||||||
border1PX: 1,
|
border1PX: 1,
|
||||||
outlineNone: 1,
|
outlineNone: 1,
|
||||||
borderColorTransparent: !shouldShowActive,
|
borderColorTransparent: !shouldShowActive,
|
||||||
@ -90,7 +89,7 @@ export default class SidebarSectionItem extends PureComponent {
|
|||||||
const countClasses = cx({
|
const countClasses = cx({
|
||||||
default: 1,
|
default: 1,
|
||||||
text: 1,
|
text: 1,
|
||||||
marginLeftAuto: 1,
|
mlAuto: 1,
|
||||||
fontSize12PX: 1,
|
fontSize12PX: 1,
|
||||||
px5: 1,
|
px5: 1,
|
||||||
mr2: 1,
|
mr2: 1,
|
||||||
|
@ -11,7 +11,7 @@ export default class SidebarSectionTitle extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.py5, _s.px10, _s.mt10].join(' ')}>
|
<div className={[_s.default, _s.py5, _s.px10, _s.mt10].join(' ')}>
|
||||||
<Text size='small' weight='bold' color='secondary'>
|
<Text size='small' weight='bold' color='tertiary'>
|
||||||
{children}
|
{children}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
@ -73,7 +73,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
isIntersecting: PropTypes.bool,
|
isIntersecting: PropTypes.bool,
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
onReply: PropTypes.func,
|
onReply: PropTypes.func,
|
||||||
onQuote: PropTypes.func,
|
onRepost: PropTypes.func,
|
||||||
onFavorite: PropTypes.func,
|
onFavorite: PropTypes.func,
|
||||||
onMention: PropTypes.func,
|
onMention: PropTypes.func,
|
||||||
onOpenMedia: PropTypes.func,
|
onOpenMedia: PropTypes.func,
|
||||||
@ -448,10 +448,12 @@ class Status extends ImmutablePureComponent {
|
|||||||
pb15: isFeatured,
|
pb15: isFeatured,
|
||||||
radiusSmall: !isChild,
|
radiusSmall: !isChild,
|
||||||
backgroundColorPrimary: !isChild,
|
backgroundColorPrimary: !isChild,
|
||||||
|
boxShadowBlock: !isChild,
|
||||||
|
outlineNone: 1,
|
||||||
mb15: !isChild,
|
mb15: !isChild,
|
||||||
border1PX: !isChild,
|
// border1PX: !isChild,
|
||||||
borderBottom1PX: isFeatured && !isChild,
|
// borderBottom1PX: isFeatured && !isChild,
|
||||||
borderColorSecondary: !isChild,
|
// borderColorSecondary: !isChild,
|
||||||
})
|
})
|
||||||
|
|
||||||
const innerContainerClasses = cx({
|
const innerContainerClasses = cx({
|
||||||
@ -510,7 +512,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
status={status}
|
status={status}
|
||||||
onFavorite={this.props.onFavorite}
|
onFavorite={this.props.onFavorite}
|
||||||
onReply={this.props.onReply}
|
onReply={this.props.onReply}
|
||||||
onQuote={this.props.onQuote}
|
onRepost={this.props.onRepost}
|
||||||
onShare={this.props.onShare}
|
onShare={this.props.onShare}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import { NavLink } from 'react-router-dom'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
import Text from './text'
|
import Text from './text'
|
||||||
import StatusActionBarItem from './status_action_bar_item'
|
import StatusActionBarItem from './status_action_bar_item'
|
||||||
@ -22,23 +23,19 @@ export default
|
|||||||
@injectIntl
|
@injectIntl
|
||||||
class StatusActionBar extends ImmutablePureComponent {
|
class StatusActionBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
router: PropTypes.object,
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
onFavorite: PropTypes.func.isRequired,
|
onFavorite: PropTypes.func.isRequired,
|
||||||
onShare: PropTypes.func.isRequired,
|
onShare: PropTypes.func.isRequired,
|
||||||
onReply: PropTypes.func.isRequired,
|
onReply: PropTypes.func.isRequired,
|
||||||
onQuote: PropTypes.func.isRequired,
|
onRepost: PropTypes.func.isRequired,
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
updateOnProps = ['status']
|
updateOnProps = ['status']
|
||||||
|
|
||||||
handleReplyClick = () => {
|
handleReplyClick = () => {
|
||||||
this.props.onReply(this.props.status, this.context.router.history)
|
this.props.onReply(this.props.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFavoriteClick = () => {
|
handleFavoriteClick = () => {
|
||||||
@ -46,8 +43,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleRepostClick = (e) => {
|
handleRepostClick = (e) => {
|
||||||
// this.props.onRepost(this.props.status, e)
|
this.props.onRepost(this.repostButton, this.props.status, e)
|
||||||
this.props.onQuote(this.props.status, this.context.router.history)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShareClick = () => {
|
handleShareClick = () => {
|
||||||
@ -66,6 +62,10 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
// : todo :
|
// : todo :
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setRepostButton = (n) => {
|
||||||
|
this.repostButton = n
|
||||||
|
}
|
||||||
|
|
||||||
setShareButton = (n) => {
|
setShareButton = (n) => {
|
||||||
this.shareButton = n
|
this.shareButton = n
|
||||||
}
|
}
|
||||||
@ -86,6 +86,8 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
!!status.get('quote')
|
!!status.get('quote')
|
||||||
) && !hasInteractions
|
) && !hasInteractions
|
||||||
|
|
||||||
|
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`
|
||||||
|
|
||||||
const containerClasses = cx({
|
const containerClasses = cx({
|
||||||
default: 1,
|
default: 1,
|
||||||
px10: 1,
|
px10: 1,
|
||||||
@ -108,6 +110,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
text: 1,
|
text: 1,
|
||||||
cursorPointer: 1,
|
cursorPointer: 1,
|
||||||
fontWeightNormal: 1,
|
fontWeightNormal: 1,
|
||||||
|
noUnderline: 1,
|
||||||
underline_onHover: 1,
|
underline_onHover: 1,
|
||||||
mr10: 1,
|
mr10: 1,
|
||||||
py5: 1,
|
py5: 1,
|
||||||
@ -117,7 +120,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
<div className={containerClasses}>
|
<div className={containerClasses}>
|
||||||
{
|
{
|
||||||
hasInteractions &&
|
hasInteractions &&
|
||||||
<div className={[_s.default, _s.flexRow, _s.px5].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.alignItemsEnd, _s.px5].join(' ')}>
|
||||||
{
|
{
|
||||||
favoriteCount > 0 &&
|
favoriteCount > 0 &&
|
||||||
<button className={interactionBtnClasses} onClick={this.openLikesList}>
|
<button className={interactionBtnClasses} onClick={this.openLikesList}>
|
||||||
@ -130,13 +133,16 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
replyCount > 0 &&
|
replyCount > 0 &&
|
||||||
<button className={interactionBtnClasses} onClick={this.toggleCommentsVisible}>
|
<NavLink
|
||||||
|
className={interactionBtnClasses}
|
||||||
|
to={statusUrl}
|
||||||
|
>
|
||||||
<Text color='secondary' size='small'>
|
<Text color='secondary' size='small'>
|
||||||
{intl.formatMessage(messages.commentsLabel, {
|
{intl.formatMessage(messages.commentsLabel, {
|
||||||
number: replyCount,
|
number: replyCount,
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</button>
|
</NavLink>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
repostCount > 0 &&
|
repostCount > 0 &&
|
||||||
@ -169,6 +175,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||||||
icon={!publicStatus ? 'lock' : 'repost'}
|
icon={!publicStatus ? 'lock' : 'repost'}
|
||||||
disabled={!publicStatus}
|
disabled={!publicStatus}
|
||||||
active={!!status.get('reblogged')}
|
active={!!status.get('reblogged')}
|
||||||
|
buttonRef={this.setRepostButton}
|
||||||
onClick={this.handleRepostClick}
|
onClick={this.handleRepostClick}
|
||||||
/>
|
/>
|
||||||
<StatusActionBarItem
|
<StatusActionBarItem
|
||||||
|
@ -76,7 +76,7 @@ class StatusCheckBox extends ImmutablePureComponent {
|
|||||||
{media}
|
{media}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.mlAuto].join(' ')}>
|
||||||
<Switch checked={checked} onChange={onToggle} disabled={disabled} />
|
<Switch checked={checked} onChange={onToggle} disabled={disabled} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -238,6 +238,7 @@ class StatusContent extends ImmutablePureComponent {
|
|||||||
const containerClasses = cx({
|
const containerClasses = cx({
|
||||||
statusContent: 1,
|
statusContent: 1,
|
||||||
px15: !isComment,
|
px15: !isComment,
|
||||||
|
outlineNone: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -58,7 +58,7 @@ class StatusHeader extends ImmutablePureComponent {
|
|||||||
render() {
|
render() {
|
||||||
const { status, reduced } = this.props
|
const { status, reduced } = this.props
|
||||||
|
|
||||||
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
|
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`
|
||||||
|
|
||||||
const containerClasses = cx({
|
const containerClasses = cx({
|
||||||
default: 1,
|
default: 1,
|
||||||
@ -93,7 +93,7 @@ class StatusHeader extends ImmutablePureComponent {
|
|||||||
to={`/${status.getIn(['account', 'acct'])}`}
|
to={`/${status.getIn(['account', 'acct'])}`}
|
||||||
title={status.getIn(['account', 'acct'])}
|
title={status.getIn(['account', 'acct'])}
|
||||||
>
|
>
|
||||||
<DisplayName account={status.get('account')} />
|
<DisplayName account={status.get('account')} noRelationship />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -105,7 +105,7 @@ class StatusHeader extends ImmutablePureComponent {
|
|||||||
icon='ellipsis'
|
icon='ellipsis'
|
||||||
iconSize='20px'
|
iconSize='20px'
|
||||||
iconClassName={_s.fillColorSecondary}
|
iconClassName={_s.fillColorSecondary}
|
||||||
className={_s.marginLeftAuto}
|
className={_s.mlAuto}
|
||||||
onClick={this.handleOpenStatusOptionsPopover}
|
onClick={this.handleOpenStatusOptionsPopover}
|
||||||
buttonRef={this.setStatusOptionsButton}
|
buttonRef={this.setStatusOptionsButton}
|
||||||
/>
|
/>
|
||||||
|
@ -50,9 +50,9 @@ class ReplyIndicator extends ImmutablePureComponent {
|
|||||||
|
|
||||||
<NavLink to={`/${status.getIn(['account', 'acct'])}`} className='reply-indicator__display-name'>
|
<NavLink to={`/${status.getIn(['account', 'acct'])}`} className='reply-indicator__display-name'>
|
||||||
<div className='reply-indicator__display-avatar'>
|
<div className='reply-indicator__display-avatar'>
|
||||||
<Avatar account={status.get('account')} size={24} />
|
<Avatar account={status.get('account')} size={24} noHover />
|
||||||
</div>
|
</div>
|
||||||
<DisplayName account={status.get('account')} />
|
<DisplayName account={status.get('account')} noHover />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export default class Switch extends PureComponent {
|
|||||||
width50PX: 1,
|
width50PX: 1,
|
||||||
circle: 1,
|
circle: 1,
|
||||||
border1PX: 1,
|
border1PX: 1,
|
||||||
marginLeftAuto: 1,
|
mlAuto: 1,
|
||||||
borderColorSecondary: 1,
|
borderColorSecondary: 1,
|
||||||
backgroundColorBrand: checked,
|
backgroundColorBrand: checked,
|
||||||
})
|
})
|
||||||
|
@ -53,9 +53,9 @@ class TimelineComposeBlock extends ImmutablePureComponent {
|
|||||||
return (
|
return (
|
||||||
<section className={[_s.default, _s.mb15].join(' ')}>
|
<section className={[_s.default, _s.mb15].join(' ')}>
|
||||||
<Block>
|
<Block>
|
||||||
<div className={[_s.default, _s.backgroundSubtle, _s.borderBottom1PX, _s.borderColorSecondary, _s.px15, _s.py2, _s.alignItemsCenter, _s.flexRow].join(' ')}>
|
<div className={[_s.default, _s.backgroundSubtle, _s.borderTop1PX, _s.borderBottom1PX, _s.borderColorSecondary, _s.px15, _s.py2, _s.alignItemsCenter, _s.flexRow].join(' ')}>
|
||||||
<div className={_s.mr10}>
|
<div className={_s.mr10}>
|
||||||
<Avatar account={account} size={20} />
|
<Avatar account={account} size={20} noHover />
|
||||||
</div>
|
</div>
|
||||||
<Heading size='h5'>
|
<Heading size='h5'>
|
||||||
{intl.formatMessage(messages.createPost)}
|
{intl.formatMessage(messages.createPost)}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
|
import { urlRegex } from '../features/compose/util/url_regex'
|
||||||
import Button from './button'
|
import Button from './button'
|
||||||
import DotTextSeperator from './dot_text_seperator'
|
import DotTextSeperator from './dot_text_seperator'
|
||||||
import Image from './image'
|
import Image from './image'
|
||||||
@ -71,6 +72,7 @@ export default class TrendingItem extends PureComponent {
|
|||||||
|
|
||||||
const correctedAuthor = author.replace('www.', '')
|
const correctedAuthor = author.replace('www.', '')
|
||||||
const correctedDescription = description.length >= 120 ? `${description.substring(0, 120).trim()}...` : description
|
const correctedDescription = description.length >= 120 ? `${description.substring(0, 120).trim()}...` : description
|
||||||
|
const descriptionHasLink = correctedDescription.match(urlRegex)
|
||||||
|
|
||||||
const image = (
|
const image = (
|
||||||
<Image
|
<Image
|
||||||
@ -105,7 +107,7 @@ export default class TrendingItem extends PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
!!correctedDescription &&
|
!!correctedDescription && !descriptionHasLink &&
|
||||||
<div className={[_s.default, _s.heightMax56PX, _s.overflowHidden, _s.pt5, _s.mb5].join(' ')}>
|
<div className={[_s.default, _s.heightMax56PX, _s.overflowHidden, _s.pt5, _s.mb5].join(' ')}>
|
||||||
<Text size='small' color='secondary'>
|
<Text size='small' color='secondary'>
|
||||||
{correctedDescription}
|
{correctedDescription}
|
||||||
|
@ -604,7 +604,7 @@ class Video extends PureComponent {
|
|||||||
className={_s.pl0}
|
className={_s.pl0}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={[_s.default, _s.marginLeftAuto, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
<div className={[_s.default, _s.mlAuto, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
<Text color='white' size='small'>
|
<Text color='white' size='small'>
|
||||||
{formatTime(currentTime)}
|
{formatTime(currentTime)}
|
||||||
/
|
/
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import classNames from 'classnames/bind'
|
||||||
|
export const CX = classNames.bind(_s)
|
||||||
|
|
||||||
export const APP_NAME = 'Gab'
|
export const APP_NAME = 'Gab'
|
||||||
|
|
||||||
export const BREAKPOINT_EXTRA_LARGE = 1480
|
export const BREAKPOINT_EXTRA_LARGE = 1480
|
||||||
@ -5,3 +8,11 @@ export const BREAKPOINT_LARGE = 1280
|
|||||||
export const BREAKPOINT_MEDIUM = 1160
|
export const BREAKPOINT_MEDIUM = 1160
|
||||||
export const BREAKPOINT_SMALL = 1080
|
export const BREAKPOINT_SMALL = 1080
|
||||||
export const BREAKPOINT_EXTRA_SMALL = 992
|
export const BREAKPOINT_EXTRA_SMALL = 992
|
||||||
|
|
||||||
|
export const ALLOWED_AROUND_SHORT_CODE = '><\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'
|
||||||
|
export const MAX_POST_CHARACTER_COUNT = 3000
|
||||||
|
|
||||||
|
export const PLACEHOLDER_MISSING_HEADER_SRC = '/headers/original/missing.png'
|
||||||
|
|
||||||
|
export const POPOVER_PROFILE_OPTIONS = 'PROFILE_OPTIONS'
|
||||||
|
export const POPOVER_USER_INFO = 'USER_INFO'
|
@ -1,18 +1,18 @@
|
|||||||
import { List as ImmutableList } from 'immutable'
|
import { List as ImmutableList } from 'immutable'
|
||||||
import { openModal } from '../../../actions/modal'
|
import { openModal } from '../actions/modal'
|
||||||
import { mentionCompose } from '../../../actions/compose'
|
import { mentionCompose } from '../actions/compose'
|
||||||
import {
|
import {
|
||||||
reblog,
|
reblog,
|
||||||
favorite,
|
favorite,
|
||||||
unreblog,
|
unreblog,
|
||||||
unfavorite,
|
unfavorite,
|
||||||
} from '../../../actions/interactions'
|
} from '../actions/interactions'
|
||||||
import {
|
import {
|
||||||
hideStatus,
|
hideStatus,
|
||||||
revealStatus,
|
revealStatus,
|
||||||
} from '../../../actions/statuses'
|
} from '../actions/statuses'
|
||||||
import { boostModal } from '../../../initial_state'
|
import { boostModal } from '../initial_state'
|
||||||
import { makeGetNotification } from '../../../selectors'
|
import { makeGetNotification } from '../selectors'
|
||||||
import Notification from '../components/notification'
|
import Notification from '../components/notification'
|
||||||
|
|
||||||
const getAccountFromState = (state, accountId) => {
|
const getAccountFromState = (state, accountId) => {
|
@ -108,21 +108,33 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onQuote (status, router) {
|
onRepost (targetRef, status, ) {
|
||||||
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
||||||
|
|
||||||
dispatch((_, getState) => {
|
dispatch(openPopover('REPOST_OPTIONS', {
|
||||||
const state = getState();
|
status,
|
||||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
targetRef,
|
||||||
dispatch(openModal('CONFIRM', {
|
position: 'top',
|
||||||
message: intl.formatMessage(messages.quoteMessage),
|
}))
|
||||||
confirm: intl.formatMessage(messages.quoteConfirm),
|
|
||||||
onConfirm: () => dispatch(quoteCompose(status, router)),
|
// if (e.shiftKey || !boostModal) {
|
||||||
}));
|
// this.onModalRepost(status);
|
||||||
} else {
|
// } else {
|
||||||
dispatch(quoteCompose(status, router));
|
// dispatch(openModal('BOOST', { status, onRepost: this.onModalRepost }));
|
||||||
}
|
// }
|
||||||
});
|
|
||||||
|
// dispatch((_, getState) => {
|
||||||
|
// const state = getState();
|
||||||
|
// if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||||
|
// dispatch(openModal('CONFIRM', {
|
||||||
|
// message: intl.formatMessage(messages.quoteMessage),
|
||||||
|
// confirm: intl.formatMessage(messages.quoteConfirm),
|
||||||
|
// onConfirm: () => dispatch(quoteCompose(status, router)),
|
||||||
|
// }));
|
||||||
|
// } else {
|
||||||
|
// dispatch(quoteCompose(status, router));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalRepost (status) {
|
onModalRepost (status) {
|
||||||
@ -143,16 +155,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
|
||||||
onRepost (status, e) {
|
|
||||||
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
|
||||||
|
|
||||||
if (e.shiftKey || !boostModal) {
|
|
||||||
this.onModalRepost(status);
|
|
||||||
} else {
|
|
||||||
dispatch(openModal('BOOST', { status, onRepost: this.onModalRepost }));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onShowRevisions (status) {
|
onShowRevisions (status) {
|
||||||
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
if (!me) return dispatch(openModal('UNAUTHORIZED'))
|
||||||
|
|
||||||
|
@ -1,28 +1,29 @@
|
|||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import classNames from 'classnames/bind'
|
|
||||||
import { length } from 'stringz'
|
import { length } from 'stringz'
|
||||||
import CharacterCounter from '../../../../components/character_counter'
|
import { isMobile } from '../../../utils/is_mobile'
|
||||||
import UploadForm from '../upload_form'
|
import { countableText } from '../util/counter'
|
||||||
import AutosuggestTextbox from '../../../../components/autosuggest_textbox'
|
import {
|
||||||
import PollButton from '../../components/poll_button'
|
CX,
|
||||||
import UploadButton from '../media_upload_button'
|
MAX_POST_CHARACTER_COUNT,
|
||||||
import SpoilerButton from '../../components/spoiler_button'
|
ALLOWED_AROUND_SHORT_CODE,
|
||||||
import RichTextEditorButton from '../../components/rich_text_editor_button'
|
} from '../../../constants'
|
||||||
import GifSelectorButton from '../../components/gif_selector_button'
|
import AutosuggestTextbox from '../../../components/autosuggest_textbox'
|
||||||
import StatusVisibilityButton from '../../components/status_visibility_button'
|
import Avatar from '../../../components/avatar'
|
||||||
import EmojiPickerButton from '../../components/emoji_picker_button'
|
import Button from '../../../components/button'
|
||||||
import PollFormContainer from '../../containers/poll_form_container'
|
import CharacterCounter from '../../../components/character_counter'
|
||||||
import SchedulePostButton from '../schedule_post_button'
|
import EmojiPickerButton from './emoji_picker_button'
|
||||||
import StatusContainer from '../../../../containers/status_container'
|
import GifSelectorButton from './gif_selector_button'
|
||||||
import Button from '../../../../components/button'
|
import PollButton from './poll_button'
|
||||||
import Avatar from '../../../../components/avatar'
|
import PollForm from './poll_form'
|
||||||
import { isMobile } from '../../../../utils/is_mobile'
|
import RichTextEditorButton from './rich_text_editor_button'
|
||||||
import { countableText } from '../../util/counter'
|
import SchedulePostButton from './schedule_post_button'
|
||||||
|
import SpoilerButton from './spoiler_button'
|
||||||
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'
|
import StatusContainer from '../../../containers/status_container'
|
||||||
const maxPostCharacterCount = 3000
|
import StatusVisibilityButton from './status_visibility_button'
|
||||||
|
import UploadButton from './media_upload_button'
|
||||||
|
import UploadForm from './upload_form'
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
placeholder: { id: 'compose_form.placeholder', defaultMessage: "What's on your mind?" },
|
placeholder: { id: 'compose_form.placeholder', defaultMessage: "What's on your mind?" },
|
||||||
@ -33,8 +34,6 @@ const messages = defineMessages({
|
|||||||
schedulePost: { id: 'compose_form.schedule_post', defaultMessage: 'Schedule Post' },
|
schedulePost: { id: 'compose_form.schedule_post', defaultMessage: 'Schedule Post' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const cx = classNames.bind(_s)
|
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@injectIntl
|
@injectIntl
|
||||||
class ComposeForm extends ImmutablePureComponent {
|
class ComposeForm extends ImmutablePureComponent {
|
||||||
@ -134,7 +133,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;
|
const { isSubmitting, isChangingUpload, isUploading, anyMedia } = this.props;
|
||||||
const fulltext = [this.props.spoilerText, countableText(this.props.text)].join('');
|
const fulltext = [this.props.spoilerText, countableText(this.props.text)].join('');
|
||||||
|
|
||||||
if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxPostCharacterCount || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
|
if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > MAX_POST_CHARACTER_COUNT || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +210,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
handleEmojiPick = (data) => {
|
handleEmojiPick = (data) => {
|
||||||
const { text } = this.props
|
const { text } = this.props
|
||||||
const position = this.autosuggestTextarea.textbox.selectionStart
|
const position = this.autosuggestTextarea.textbox.selectionStart
|
||||||
const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1])
|
const needsSpace = data.custom && position > 0 && !ALLOWED_AROUND_SHORT_CODE.includes(text[position - 1])
|
||||||
|
|
||||||
this.props.onPickEmoji(position, data, needsSpace)
|
this.props.onPickEmoji(position, data, needsSpace)
|
||||||
}
|
}
|
||||||
@ -240,17 +239,17 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
} = this.props
|
} = this.props
|
||||||
const disabled = isSubmitting
|
const disabled = isSubmitting
|
||||||
const text = [this.props.spoilerText, countableText(this.props.text)].join('');
|
const text = [this.props.spoilerText, countableText(this.props.text)].join('');
|
||||||
const disabledButton = disabled || isUploading || isChangingUpload || length(text) > maxPostCharacterCount || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
|
const disabledButton = disabled || isUploading || isChangingUpload || length(text) > MAX_POST_CHARACTER_COUNT || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
|
||||||
const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth)
|
const shouldAutoFocus = autoFocus && !showSearch && !isMobile(window.innerWidth)
|
||||||
|
|
||||||
const parentContainerClasses = cx({
|
const parentContainerClasses = CX({
|
||||||
default: 1,
|
default: 1,
|
||||||
width100PC: 1,
|
width100PC: 1,
|
||||||
flexRow: !shouldCondense,
|
flexRow: !shouldCondense,
|
||||||
pb10: !shouldCondense,
|
pb10: !shouldCondense,
|
||||||
})
|
})
|
||||||
|
|
||||||
const childContainerClasses = cx({
|
const childContainerClasses = CX({
|
||||||
default: 1,
|
default: 1,
|
||||||
flexWrap: 1,
|
flexWrap: 1,
|
||||||
overflowHidden: 1,
|
overflowHidden: 1,
|
||||||
@ -262,17 +261,17 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
px5: shouldCondense,
|
px5: shouldCondense,
|
||||||
})
|
})
|
||||||
|
|
||||||
const actionsContainerClasses = cx({
|
const actionsContainerClasses = CX({
|
||||||
default: 1,
|
default: 1,
|
||||||
flexRow: 1,
|
flexRow: 1,
|
||||||
alignItemsCenter: !shouldCondense,
|
alignItemsCenter: !shouldCondense,
|
||||||
alignItemsStart: shouldCondense,
|
alignItemsStart: shouldCondense,
|
||||||
mt10: !shouldCondense,
|
mt10: !shouldCondense,
|
||||||
px15: !shouldCondense,
|
px15: !shouldCondense,
|
||||||
marginLeftAuto: shouldCondense,
|
mlAuto: shouldCondense,
|
||||||
})
|
})
|
||||||
|
|
||||||
const commentPublishBtnClasses = cx({
|
const commentPublishBtnClasses = CX({
|
||||||
default: 1,
|
default: 1,
|
||||||
justifyContentCenter: 1,
|
justifyContentCenter: 1,
|
||||||
displayNone: length(this.props.text) === 0 || anyMedia,
|
displayNone: length(this.props.text) === 0 || anyMedia,
|
||||||
@ -284,7 +283,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
{
|
{
|
||||||
shouldCondense &&
|
shouldCondense &&
|
||||||
<div className={[_s.default, _s.mr10, _s.mt5].join(' ')}>
|
<div className={[_s.default, _s.mr10, _s.mt5].join(' ')}>
|
||||||
<Avatar account={account} size={28} />
|
<Avatar account={account} size={28} noHover />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +360,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
{
|
{
|
||||||
!edit && hasPoll &&
|
!edit && hasPoll &&
|
||||||
<div className={[_s.default, _s.px15, _s.mt5].join(' ')}>
|
<div className={[_s.default, _s.px15, _s.mt5].join(' ')}>
|
||||||
<PollFormContainer replyToId={replyToId} />
|
<PollForm replyToId={replyToId} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +375,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div className={actionsContainerClasses}>
|
<div className={actionsContainerClasses}>
|
||||||
<div className={[_s.default, _s.flexRow, _s.marginRightAuto].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
|
||||||
{
|
{
|
||||||
!shouldCondense &&
|
!shouldCondense &&
|
||||||
<RichTextEditorButton />
|
<RichTextEditorButton />
|
||||||
@ -418,7 +417,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!shouldCondense &&
|
!shouldCondense &&
|
||||||
<CharacterCounter max={maxPostCharacterCount} text={text} />
|
<CharacterCounter max={MAX_POST_CHARACTER_COUNT} text={text} />
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
@ -1,144 +0,0 @@
|
|||||||
.compose-form {
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
&__sensitive-button {
|
|
||||||
padding: 0 10px 10px 10px;
|
|
||||||
|
|
||||||
@include text-sizing(14px, 500);
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=checkbox] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
box-sizing: border-box;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-right: 10px;
|
|
||||||
top: -1px;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
@include size(18px);
|
|
||||||
@include border-design($ui-primary-color, 1px, 4px);
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: $highlight-text-color;
|
|
||||||
background: $highlight-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-dropdown {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 5px;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.condensed {
|
|
||||||
.autosuggest-textarea__textarea {
|
|
||||||
min-height: 46px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-wrapper {
|
|
||||||
position: relative;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__modifiers {
|
|
||||||
color: $inverted-text-color;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 14px;
|
|
||||||
background: $simple-background-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons-wrapper {
|
|
||||||
padding: 10px;
|
|
||||||
background: darken($simple-background-color, 8%);
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
@include flex(space-between);
|
|
||||||
|
|
||||||
.compose-form__buttons {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.compose-form__sensitive-button {
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&.compose-form__sensitive-button--visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__sensitive-button__icon {
|
|
||||||
line-height: 27px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
box-sizing: content-box;
|
|
||||||
padding: 0 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__publish {
|
|
||||||
min-width: 0;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
@include flex(flex-end);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__publish-button-wrapper {
|
|
||||||
overflow: hidden;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.spoiler-input {
|
|
||||||
height: 0;
|
|
||||||
transform-origin: bottom;
|
|
||||||
opacity: 0.0;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&--visible {
|
|
||||||
height: 36px;
|
|
||||||
margin-bottom: 11px;
|
|
||||||
opacity: 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__input {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
color: $inverted-text-color;
|
|
||||||
background: $simple-background-color;
|
|
||||||
padding: 10px;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 14px;
|
|
||||||
resize: vertical;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include breakpoint(sm) {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-reduce-motion .spoiler-input {
|
|
||||||
transition: height 0.4s ease, opacity 0.4s ease;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export { default } from './compose_form'
|
|
@ -1,117 +0,0 @@
|
|||||||
.emoji-picker-dropdown__menu {
|
|
||||||
background: $simple-background-color;
|
|
||||||
position: absolute;
|
|
||||||
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
|
|
||||||
border-radius: 4px;
|
|
||||||
margin-top: 5px;
|
|
||||||
z-index: 20000;
|
|
||||||
|
|
||||||
.emoji-mart-scroll {
|
|
||||||
transition: opacity 200ms ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selecting .emoji-mart-scroll {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-dropdown__modifiers {
|
|
||||||
position: absolute;
|
|
||||||
top: 60px;
|
|
||||||
right: 11px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-picker-dropdown__modifiers__menu {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 4;
|
|
||||||
top: -4px;
|
|
||||||
left: -8px;
|
|
||||||
background: $simple-background-color;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
button {
|
|
||||||
display: block;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 0;
|
|
||||||
padding: 4px 8px;
|
|
||||||
background: transparent;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
background: rgba($ui-secondary-color, 0.4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-emoji {
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-button {
|
|
||||||
display: block;
|
|
||||||
margin-left: 2px;
|
|
||||||
width: 24px;
|
|
||||||
outline: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
@include text-sizing(24px, 400, 24px);
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
opacity: 0.8;
|
|
||||||
display: block;
|
|
||||||
margin: 2px 0 0 0;
|
|
||||||
|
|
||||||
@include size(22px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
img {
|
|
||||||
opacity: 1;
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-reduce-motion .pulse-loading {
|
|
||||||
transform-origin: center center;
|
|
||||||
animation: heartbeat 1.5s ease-in-out infinite both;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes heartbeat {
|
|
||||||
from {
|
|
||||||
transform: scale(1);
|
|
||||||
animation-timing-function: ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
10% {
|
|
||||||
transform: scale(0.91);
|
|
||||||
animation-timing-function: ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
17% {
|
|
||||||
transform: scale(0.98);
|
|
||||||
animation-timing-function: ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
33% {
|
|
||||||
transform: scale(0.87);
|
|
||||||
animation-timing-function: ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
45% {
|
|
||||||
transform: scale(1);
|
|
||||||
animation-timing-function: ease-out;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export { default } from './emoji_picker_dropdown'
|
|
@ -2,6 +2,15 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
|
|||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import {
|
||||||
|
addPollOption,
|
||||||
|
removePollOption,
|
||||||
|
changePollOption,
|
||||||
|
changePollSettings,
|
||||||
|
clearComposeSuggestions,
|
||||||
|
fetchComposeSuggestions,
|
||||||
|
selectComposeSuggestion,
|
||||||
|
} from '../../../actions/compose'
|
||||||
import Button from '../../../components/button'
|
import Button from '../../../components/button'
|
||||||
import Text from '../../../components/text'
|
import Text from '../../../components/text'
|
||||||
import Select from '../../../components/select'
|
import Select from '../../../components/select'
|
||||||
@ -19,108 +28,47 @@ const messages = defineMessages({
|
|||||||
days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
|
days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
|
||||||
})
|
})
|
||||||
|
|
||||||
@injectIntl
|
const mapStateToProps = (state) => ({
|
||||||
class PollFormOption extends ImmutablePureComponent {
|
suggestions: state.getIn(['compose', 'suggestions']),
|
||||||
|
options: state.getIn(['compose', 'poll', 'options']),
|
||||||
|
expiresIn: state.getIn(['compose', 'poll', 'expires_in']),
|
||||||
|
isMultiple: state.getIn(['compose', 'poll', 'multiple']),
|
||||||
|
})
|
||||||
|
|
||||||
static propTypes = {
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
title: PropTypes.string.isRequired,
|
onAddOption() {
|
||||||
index: PropTypes.number.isRequired,
|
dispatch(addPollOption(''))
|
||||||
isPollMultiple: PropTypes.bool,
|
},
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
onRemove: PropTypes.func.isRequired,
|
|
||||||
onToggleMultiple: PropTypes.func.isRequired,
|
|
||||||
suggestions: ImmutablePropTypes.list,
|
|
||||||
onClearSuggestions: PropTypes.func.isRequired,
|
|
||||||
onFetchSuggestions: PropTypes.func.isRequired,
|
|
||||||
onSuggestionSelected: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOptionTitleChange = e => {
|
onRemoveOption(index) {
|
||||||
this.props.onChange(this.props.index, e.target.value);
|
dispatch(removePollOption(index))
|
||||||
}
|
},
|
||||||
|
|
||||||
handleOptionRemove = () => {
|
onChangeOption(index, title) {
|
||||||
this.props.onRemove(this.props.index);
|
dispatch(changePollOption(index, title))
|
||||||
}
|
},
|
||||||
|
|
||||||
handleToggleMultiple = e => {
|
onChangeSettings(expiresIn, isMultiple) {
|
||||||
this.props.onToggleMultiple();
|
dispatch(changePollSettings(expiresIn, isMultiple))
|
||||||
e.preventDefault();
|
},
|
||||||
e.stopPropagation();
|
|
||||||
};
|
|
||||||
|
|
||||||
onSuggestionsClearRequested = () => {
|
onClearSuggestions () {
|
||||||
this.props.onClearSuggestions();
|
dispatch(clearComposeSuggestions())
|
||||||
}
|
},
|
||||||
|
|
||||||
onSuggestionsFetchRequested = (token) => {
|
onFetchSuggestions (token) {
|
||||||
this.props.onFetchSuggestions(token);
|
dispatch(fetchComposeSuggestions(token))
|
||||||
}
|
},
|
||||||
|
|
||||||
onSuggestionSelected = (tokenStart, token, value) => {
|
onSuggestionSelected (position, token, accountId, path) {
|
||||||
this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]);
|
dispatch(selectComposeSuggestion(position, token, accountId, path))
|
||||||
}
|
},
|
||||||
|
|
||||||
render() {
|
})
|
||||||
const { isPollMultiple, title, index, intl } = this.props;
|
|
||||||
|
|
||||||
const toggleClasses = cx({
|
|
||||||
default: 1,
|
|
||||||
px10: 1,
|
|
||||||
py10: 1,
|
|
||||||
borderColorSecondary: 1,
|
|
||||||
border1PX: 1,
|
|
||||||
outlineNone: 1,
|
|
||||||
mr10: 1,
|
|
||||||
circle: !isPollMultiple,
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className={[_s.default, _s.flexRow, _s.mb10].join(' ')}>
|
|
||||||
<label className={[_s.default, _s.flexRow, _s.flexGrow1, _s.alignItemsCenter].join(' ')}>
|
|
||||||
<span
|
|
||||||
className={toggleClasses}
|
|
||||||
onClick={this.handleToggleMultiple}
|
|
||||||
role='button'
|
|
||||||
tabIndex='0'
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AutosuggestTextbox
|
|
||||||
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
|
||||||
maxLength={25}
|
|
||||||
value={title}
|
|
||||||
onChange={this.handleOptionTitleChange}
|
|
||||||
suggestions={this.props.suggestions}
|
|
||||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
|
||||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
|
||||||
onSuggestionSelected={this.onSuggestionSelected}
|
|
||||||
searchTokens={[':']}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
{
|
|
||||||
index > 1 &&
|
|
||||||
<Button
|
|
||||||
isNarrow
|
|
||||||
backgroundColor='none'
|
|
||||||
className={[_s.ml5, _s.justifyContentCenter].join(' ')}
|
|
||||||
icon='close'
|
|
||||||
iconSize='8px'
|
|
||||||
iconClassName={_s.fillColorSecondary}
|
|
||||||
disabled={index <= 1}
|
|
||||||
title={intl.formatMessage(messages.remove_option)}
|
|
||||||
onClick={this.handleOptionRemove}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@injectIntl
|
@injectIntl
|
||||||
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
class PollForm extends ImmutablePureComponent {
|
class PollForm extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -166,6 +114,7 @@ class PollForm extends ImmutablePureComponent {
|
|||||||
{
|
{
|
||||||
options.map((title, i) => (
|
options.map((title, i) => (
|
||||||
<PollFormOption
|
<PollFormOption
|
||||||
|
intl={intl}
|
||||||
title={title}
|
title={title}
|
||||||
key={`poll-form-option-${i}`}
|
key={`poll-form-option-${i}`}
|
||||||
index={i}
|
index={i}
|
||||||
@ -241,3 +190,102 @@ class PollForm extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PollFormOption extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
isPollMultiple: PropTypes.bool,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
onRemove: PropTypes.func.isRequired,
|
||||||
|
onToggleMultiple: PropTypes.func.isRequired,
|
||||||
|
suggestions: ImmutablePropTypes.list,
|
||||||
|
onClearSuggestions: PropTypes.func.isRequired,
|
||||||
|
onFetchSuggestions: PropTypes.func.isRequired,
|
||||||
|
onSuggestionSelected: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOptionTitleChange = e => {
|
||||||
|
this.props.onChange(this.props.index, e.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOptionRemove = () => {
|
||||||
|
this.props.onRemove(this.props.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleToggleMultiple = e => {
|
||||||
|
this.props.onToggleMultiple()
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionsClearRequested = () => {
|
||||||
|
this.props.onClearSuggestions()
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionsFetchRequested = (token) => {
|
||||||
|
this.props.onFetchSuggestions(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionSelected = (tokenStart, token, value) => {
|
||||||
|
this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index])
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isPollMultiple, title, index, intl } = this.props
|
||||||
|
|
||||||
|
const toggleClasses = cx({
|
||||||
|
default: 1,
|
||||||
|
px10: 1,
|
||||||
|
py10: 1,
|
||||||
|
borderColorSecondary: 1,
|
||||||
|
border1PX: 1,
|
||||||
|
outlineNone: 1,
|
||||||
|
mr10: 1,
|
||||||
|
circle: !isPollMultiple,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className={[_s.default, _s.flexRow, _s.mb10].join(' ')}>
|
||||||
|
<label className={[_s.default, _s.flexRow, _s.flexGrow1, _s.alignItemsCenter].join(' ')}>
|
||||||
|
<span
|
||||||
|
className={toggleClasses}
|
||||||
|
onClick={this.handleToggleMultiple}
|
||||||
|
role='button'
|
||||||
|
tabIndex='0'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AutosuggestTextbox
|
||||||
|
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
||||||
|
maxLength={25}
|
||||||
|
value={title}
|
||||||
|
onChange={this.handleOptionTitleChange}
|
||||||
|
suggestions={this.props.suggestions}
|
||||||
|
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||||
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||||
|
onSuggestionSelected={this.onSuggestionSelected}
|
||||||
|
searchTokens={[':']}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{
|
||||||
|
index > 1 &&
|
||||||
|
<Button
|
||||||
|
isNarrow
|
||||||
|
backgroundColor='none'
|
||||||
|
className={[_s.ml5, _s.justifyContentCenter].join(' ')}
|
||||||
|
icon='close'
|
||||||
|
iconSize='8px'
|
||||||
|
iconClassName={_s.fillColorSecondary}
|
||||||
|
disabled={index <= 1}
|
||||||
|
title={intl.formatMessage(messages.remove_option)}
|
||||||
|
onClick={this.handleOptionRemove}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,20 +1,33 @@
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl'
|
||||||
import HashtagItem from '../../../../components/hashtag_item'
|
import { withRouter } from 'react-router-dom';
|
||||||
import Icon from '../../../../components/icon'
|
import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestions';
|
||||||
import { WhoToFollowPanel } from '../../../../components/panel'
|
import HashtagItem from '../../../components/hashtag_item'
|
||||||
|
import Icon from '../../../components/icon'
|
||||||
|
import { WhoToFollowPanel } from '../../../components/panel'
|
||||||
// import TrendsPanel from '../../ui/components/trends_panel'
|
// import TrendsPanel from '../../ui/components/trends_panel'
|
||||||
import GroupListItem from '../../../../components/group_list_item'
|
import GroupListItem from '../../../components/group_list_item'
|
||||||
import Block from '../../../../components/block'
|
import Block from '../../../components/block'
|
||||||
import Heading from '../../../../components/heading'
|
import Heading from '../../../components/heading'
|
||||||
import Button from '../../../../components/button'
|
import Button from '../../../components/button'
|
||||||
import Text from '../../../../components/text'
|
import Text from '../../../components/text'
|
||||||
import Account from '../../../../components/account'
|
import Account from '../../../components/account'
|
||||||
|
|
||||||
// : todo :
|
const mapStateToProps = (state) => ({
|
||||||
|
results: state.getIn(['search', 'results']),
|
||||||
|
suggestions: state.getIn(['suggestions', 'items']),
|
||||||
|
});
|
||||||
|
|
||||||
export default class SearchResults extends ImmutablePureComponent {
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
fetchSuggestions: () => dispatch(fetchSuggestions()),
|
||||||
|
dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default
|
||||||
|
@withRouter
|
||||||
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
class SearchResults extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
results: ImmutablePropTypes.map.isRequired,
|
results: ImmutablePropTypes.map.isRequired,
|
||||||
@ -46,12 +59,12 @@ export default class SearchResults extends ImmutablePureComponent {
|
|||||||
if (results.get('accounts') && results.get('accounts').size > 0 && (isTop || showPeople)) {
|
if (results.get('accounts') && results.get('accounts').size > 0 && (isTop || showPeople)) {
|
||||||
const size = isTop ? Math.min(results.get('accounts').size, 5) : results.get('accounts').size;
|
const size = isTop ? Math.min(results.get('accounts').size, 5) : results.get('accounts').size;
|
||||||
accounts = (
|
accounts = (
|
||||||
<div className={[_s.default, _s.py15, _s.px15].join(' ')}>
|
<div className={[_s.default, _s.py15].join(' ')}>
|
||||||
<div className={[_s.default, _s.flexRow, _s.mb15].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.mb15, _s.px15].join(' ')}>
|
||||||
<Heading size='h3'>
|
<Heading size='h2'>
|
||||||
People
|
People
|
||||||
</Heading>
|
</Heading>
|
||||||
<div className={[_s.default, _s.marginLeftAuto].join(' ')}>
|
<div className={[_s.default, _s.mlAuto].join(' ')}>
|
||||||
<Button
|
<Button
|
||||||
isText
|
isText
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
@ -66,7 +79,7 @@ export default class SearchResults extends ImmutablePureComponent {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
results.get('accounts').slice(0, size).map(accountId => <Account expanded key={accountId} id={accountId} />)
|
results.get('accounts').slice(0, size).map(accountId => <Account compact key={accountId} id={accountId} />)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
@ -1 +0,0 @@
|
|||||||
export { default } from './search_results'
|
|
@ -1,40 +0,0 @@
|
|||||||
.search-results {
|
|
||||||
&__header {
|
|
||||||
color: $dark-text-color;
|
|
||||||
background: lighten($ui-base-color, 2%);
|
|
||||||
padding: 15px;
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
@include text-sizing(16px, 500);
|
|
||||||
|
|
||||||
.fa {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__section {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
display: flex;
|
|
||||||
background: darken($ui-base-color, 4%);
|
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
|
||||||
color: $dark-text-color;
|
|
||||||
padding: 15px;
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
@include text-sizing(16px, 500);
|
|
||||||
|
|
||||||
.fa {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account:last-child,
|
|
||||||
&>div:last-child .status {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,7 +11,7 @@ import { mascot } from '../../initial_state';
|
|||||||
import Motion from '../ui/util/optional_motion';
|
import Motion from '../ui/util/optional_motion';
|
||||||
import ComposeFormContainer from './containers/compose_form_container';
|
import ComposeFormContainer from './containers/compose_form_container';
|
||||||
// import SearchContainer from './containers/search_container';
|
// import SearchContainer from './containers/search_container';
|
||||||
import SearchResultsContainer from './containers/search_results_container';
|
import SearchResults from './components/search_results';
|
||||||
import NavigationBar from './components/navigation_bar';
|
import NavigationBar from './components/navigation_bar';
|
||||||
import elephantUIPlane from '../../../images/logo_ui_column_footer.png';
|
import elephantUIPlane from '../../../images/logo_ui_column_footer.png';
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ class Compose extends ImmutablePureComponent {
|
|||||||
<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 }) => (
|
{({ 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 />
|
<SearchResults />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Motion>
|
</Motion>
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
.drawer {
|
|
||||||
width: 300px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__tab {
|
|
||||||
display: block;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
padding: 15px 5px 13px;
|
|
||||||
color: $darker-text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 16px;
|
|
||||||
border-bottom: 2px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer {
|
|
||||||
flex: 1 1 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__pager {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
flex-grow: 1;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__inner {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
background: lighten($ui-base-color, 13%);
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
@include size(100%);
|
|
||||||
|
|
||||||
&.darker {
|
|
||||||
background: $ui-base-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__inner__gabsocial {
|
|
||||||
background: lighten($ui-base-color, 13%) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto;
|
|
||||||
flex: 1;
|
|
||||||
min-height: 47px;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
>img {
|
|
||||||
display: block;
|
|
||||||
object-fit: contain;
|
|
||||||
object-position: bottom left;
|
|
||||||
pointer-events: none;
|
|
||||||
user-drag: none;
|
|
||||||
|
|
||||||
@include unselectable;
|
|
||||||
@include size(100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-height: 640px) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.drawer__header {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
font-size: 16px;
|
|
||||||
background: lighten($ui-base-color, 8%);
|
|
||||||
margin-bottom: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
a {
|
|
||||||
transition: background 100ms ease-in;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: lighten($ui-base-color, 3%);
|
|
||||||
transition: background 200ms ease-out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 631px) {
|
|
||||||
.drawer {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
@include horizontal-padding(5px);
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
import PollForm from '../components/poll_form';
|
|
||||||
import { addPollOption, removePollOption, changePollOption, changePollSettings } from '../../../actions/compose';
|
|
||||||
import {
|
|
||||||
clearComposeSuggestions,
|
|
||||||
fetchComposeSuggestions,
|
|
||||||
selectComposeSuggestion,
|
|
||||||
} from '../../../actions/compose';
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
suggestions: state.getIn(['compose', 'suggestions']),
|
|
||||||
options: state.getIn(['compose', 'poll', 'options']),
|
|
||||||
expiresIn: state.getIn(['compose', 'poll', 'expires_in']),
|
|
||||||
isMultiple: state.getIn(['compose', 'poll', 'multiple']),
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
onAddOption() {
|
|
||||||
dispatch(addPollOption(''))
|
|
||||||
},
|
|
||||||
|
|
||||||
onRemoveOption(index) {
|
|
||||||
dispatch(removePollOption(index));
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeOption(index, title) {
|
|
||||||
dispatch(changePollOption(index, title));
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeSettings(expiresIn, isMultiple) {
|
|
||||||
dispatch(changePollSettings(expiresIn, isMultiple));
|
|
||||||
},
|
|
||||||
|
|
||||||
onClearSuggestions () {
|
|
||||||
dispatch(clearComposeSuggestions());
|
|
||||||
},
|
|
||||||
|
|
||||||
onFetchSuggestions (token) {
|
|
||||||
dispatch(fetchComposeSuggestions(token));
|
|
||||||
},
|
|
||||||
|
|
||||||
onSuggestionSelected (position, token, accountId, path) {
|
|
||||||
dispatch(selectComposeSuggestion(position, token, accountId, path));
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PollForm);
|
|
@ -1,15 +0,0 @@
|
|||||||
import SearchResults from '../components/search_results';
|
|
||||||
import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestions';
|
|
||||||
import { withRouter } from 'react-router-dom';
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
results: state.getIn(['search', 'results']),
|
|
||||||
suggestions: state.getIn(['suggestions', 'items']),
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
fetchSuggestions: () => dispatch(fetchSuggestions()),
|
|
||||||
dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(SearchResults));
|
|
@ -74,12 +74,12 @@ class Followers extends ImmutablePureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Block>
|
<Block>
|
||||||
<div className={[_s.default, _s.px15, _s.py10, _s.justifyContentCenter, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}>
|
<div className={[_s.default, _s.px15, _s.py10, _s.justifyContentCenter].join(' ')}>
|
||||||
<Heading size='h3'>
|
<Heading size='h2'>
|
||||||
{intl.formatMessage(messages.followers)}
|
{intl.formatMessage(messages.followers)}
|
||||||
</Heading>
|
</Heading>
|
||||||
</div>
|
</div>
|
||||||
<div className={[_s.default, _s.px15, _s.py10].join(' ')}>
|
<div className={[_s.default, _s.py10].join(' ')}>
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='followers'
|
scrollKey='followers'
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
|
@ -74,12 +74,12 @@ class Following extends ImmutablePureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Block>
|
<Block>
|
||||||
<div className={[_s.default, _s.px15, _s.py10, _s.justifyContentCenter, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}>
|
<div className={[_s.default, _s.px15, _s.py10, _s.justifyContentCenter].join(' ')}>
|
||||||
<Heading size='h3'>
|
<Heading size='h2'>
|
||||||
{intl.formatMessage(messages.follows)}
|
{intl.formatMessage(messages.follows)}
|
||||||
</Heading>
|
</Heading>
|
||||||
</div>
|
</div>
|
||||||
<div className={[_s.default, _s.px15, _s.py10].join(' ')}>
|
<div className={[_s.default, _s.py10].join(' ')}>
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='following'
|
scrollKey='following'
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
|
@ -8,13 +8,13 @@ import {
|
|||||||
expandNotifications,
|
expandNotifications,
|
||||||
scrollTopNotifications,
|
scrollTopNotifications,
|
||||||
dequeueNotifications,
|
dequeueNotifications,
|
||||||
} from '../../actions/notifications'
|
} from '../actions/notifications'
|
||||||
import NotificationContainer from './containers/notification_container'
|
import NotificationContainer from '../containers/notification_container'
|
||||||
// import ColumnSettingsContainer from './containers/column_settings_container'
|
// import ColumnSettingsContainer from './containers/column_settings_container'
|
||||||
import ScrollableList from '../../components/scrollable_list'
|
import ScrollableList from '../components/scrollable_list'
|
||||||
import LoadMore from '../../components/load_more'
|
import LoadMore from '../components/load_more'
|
||||||
import TimelineQueueButtonHeader from '../../components/timeline_queue_button_header'
|
import TimelineQueueButtonHeader from '../components/timeline_queue_button_header'
|
||||||
import Block from '../../components/block'
|
import Block from '../components/block'
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
notifications: state.getIn(['notifications', 'items']),
|
notifications: state.getIn(['notifications', 'items']),
|
@ -1 +0,0 @@
|
|||||||
export { default } from './notifications'
|
|
@ -1,5 +1,5 @@
|
|||||||
// import SearchContainer from '../compose/containers/search_container';
|
// import SearchContainer from '../compose/containers/search_container';
|
||||||
import SearchResultsContainer from './compose/containers/search_results_container';
|
import SearchResults from './compose/components/search_results';
|
||||||
|
|
||||||
export default class Search extends PureComponent {
|
export default class Search extends PureComponent {
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ export default class Search extends PureComponent {
|
|||||||
|
|
||||||
<div className='drawer__pager'>
|
<div className='drawer__pager'>
|
||||||
<div className='drawer__inner darker'>
|
<div className='drawer__inner darker'>
|
||||||
<SearchResultsContainer />
|
<SearchResults />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -207,6 +207,10 @@ body {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.borderColorSecondary3 {
|
||||||
|
border-color: #F6F6F9;
|
||||||
|
}
|
||||||
|
|
||||||
.borderColorSecondary2 {
|
.borderColorSecondary2 {
|
||||||
border-color: #e5e9ed;
|
border-color: #e5e9ed;
|
||||||
}
|
}
|
||||||
@ -251,6 +255,10 @@ body {
|
|||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border6PX {
|
||||||
|
border-width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.borderBottom2PX {
|
.borderBottom2PX {
|
||||||
border-bottom-width: 2px;
|
border-bottom-width: 2px;
|
||||||
}
|
}
|
||||||
@ -307,12 +315,36 @@ body {
|
|||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.backgroundCandy {
|
||||||
|
background-image: linear-gradient(-45deg,
|
||||||
|
rgba(255, 255, 255, 0.15) 10%,
|
||||||
|
rgba(255, 255, 255, 0) 10%,
|
||||||
|
rgba(255, 255, 255, 0) 20%,
|
||||||
|
rgba(255, 255, 255, 0.15) 20%,
|
||||||
|
rgba(255, 255, 255, 0.15) 30%,
|
||||||
|
rgba(255, 255, 255, 0) 30%,
|
||||||
|
rgba(255, 255, 255, 0) 40%,
|
||||||
|
rgba(255, 255, 255, 0.15) 40%,
|
||||||
|
rgba(255, 255, 255, 0.15) 50%,
|
||||||
|
rgba(255, 255, 255, 0) 50%,
|
||||||
|
rgba(255, 255, 255, 0) 60%,
|
||||||
|
rgba(255, 255, 255, 0.15) 60%,
|
||||||
|
rgba(255, 255, 255, 0.15) 70%,
|
||||||
|
rgba(255, 255, 255, 0) 70%,
|
||||||
|
rgba(255, 255, 255, 0) 80%,
|
||||||
|
rgba(255, 255, 255, 0.15) 80%,
|
||||||
|
rgba(255, 255, 255, 0.15) 90%,
|
||||||
|
rgba(255, 255, 255, 0) 90%,
|
||||||
|
rgba(255, 255, 255, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
.backgroundTransparent {
|
.backgroundTransparent {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.backgroundPanel {
|
.backgroundPanel {
|
||||||
background-color: #aaa;
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.backgroundSubtle {
|
.backgroundSubtle {
|
||||||
@ -827,8 +859,8 @@ body {
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shadow {
|
.textShadow {
|
||||||
/* todo */
|
text-shadow: 0 0 5px #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.z1 {
|
.z1 {
|
||||||
@ -897,11 +929,11 @@ body {
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.marginLeftAuto {
|
.mlAuto {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.marginRightAuto {
|
.mrAuto {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,8 +961,8 @@ body {
|
|||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mtNeg30PX {
|
.mtNeg32PX {
|
||||||
margin-top: -30px;
|
margin-top: -32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mtNeg75PX {
|
.mtNeg75PX {
|
||||||
@ -982,6 +1014,10 @@ body {
|
|||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pl25 {
|
||||||
|
padding-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
.pr0 {
|
.pr0 {
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
@ -1049,6 +1085,22 @@ body {
|
|||||||
box-shadow: 0 0 15px -5px rgba(0,0,0,0.15);
|
box-shadow: 0 0 15px -5px rgba(0,0,0,0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.boxShadowBlock {
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.boxShadowNone .boxShadowBlock {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boxShadowAvatarPro {
|
||||||
|
box-shadow: 0 0 0 2px #F7D230;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boxShadowProfileAvatar {
|
||||||
|
box-shadow: 0 0 0 6px #F6F6F9;
|
||||||
|
}
|
||||||
|
|
||||||
.listStyleNone {
|
.listStyleNone {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user