Progress
This commit is contained in:
@@ -35,6 +35,7 @@ class Account extends ImmutablePureComponent {
|
||||
actionTitle: PropTypes.string,
|
||||
onActionClick: PropTypes.func,
|
||||
compact: PropTypes.bool,
|
||||
expanded: PropTypes.bool,
|
||||
showDismiss: PropTypes.bool,
|
||||
dismissAction: PropTypes.func,
|
||||
}
|
||||
@@ -76,6 +77,7 @@ class Account extends ImmutablePureComponent {
|
||||
actionIcon,
|
||||
actionTitle,
|
||||
compact,
|
||||
expanded,
|
||||
dismissAction,
|
||||
showDismiss,
|
||||
} = this.props
|
||||
|
||||
@@ -35,13 +35,13 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
onBlur: PropTypes.func,
|
||||
textarea: PropTypes.bool,
|
||||
small: PropTypes.bool,
|
||||
};
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
autoFocus: true,
|
||||
searchTokens: ['@', ':', '#'],
|
||||
textarea: false,
|
||||
};
|
||||
}
|
||||
|
||||
state = {
|
||||
suggestionsHidden: true,
|
||||
@@ -49,11 +49,13 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
selectedSuggestion: 0,
|
||||
lastToken: null,
|
||||
tokenStart: 0,
|
||||
};
|
||||
}
|
||||
|
||||
onChange = (e) => {
|
||||
const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart, this.props.searchTokens);
|
||||
|
||||
console.log('onChange', e.target.value, e.target, this.textbox, tokenStart, token)
|
||||
|
||||
if (token !== null && this.state.lastToken !== token) {
|
||||
this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });
|
||||
this.props.onSuggestionsFetchRequested(token);
|
||||
@@ -155,10 +157,6 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
setTextbox = (c) => {
|
||||
this.textbox = c;
|
||||
}
|
||||
|
||||
renderSuggestion = (suggestion, i) => {
|
||||
const { selectedSuggestion } = this.state;
|
||||
let inner, key;
|
||||
@@ -192,6 +190,10 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
setTextbox = (c) => {
|
||||
this.textbox = c;
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
value,
|
||||
@@ -249,12 +251,15 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
<Fragment>
|
||||
<div className={[_s.default, _s.flexGrow1].join(' ')}>
|
||||
<div className={[_s.default, _s.ml5].join(' ')}>
|
||||
<Textarea
|
||||
className={_s.default}
|
||||
inputRef={this.setTextbox}
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
aria-autocomplete='list'
|
||||
/>
|
||||
|
||||
<ContentEditable
|
||||
noFocuscontainerRefocus
|
||||
ariaMultiline
|
||||
contentEditable
|
||||
spellcheck
|
||||
tabindex='0'
|
||||
ariaLabel='Gab text'
|
||||
role='textbox'
|
||||
@@ -264,9 +269,10 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
'white-space': 'pre-wrap',
|
||||
overflowWrap: 'break-word'
|
||||
}}
|
||||
inputRef={this.setTextbox}
|
||||
className={textClasses}
|
||||
disabled={disabled}
|
||||
style={style}
|
||||
html={value}
|
||||
placeholder={placeholder}
|
||||
autoFocus={autoFocus}
|
||||
onChange={this.onChange}
|
||||
@@ -275,8 +281,6 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
onPaste={this.onPaste}
|
||||
style={style}
|
||||
html={value}
|
||||
/>
|
||||
</div>
|
||||
{children}
|
||||
|
||||
@@ -14,14 +14,21 @@ class Avatar extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
account: ImmutableMap(),
|
||||
animate: autoPlayGif,
|
||||
size: 40,
|
||||
}
|
||||
|
||||
state = {
|
||||
hovering: false,
|
||||
sameImg: 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'),
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (prevProps.account !== this.props.account) {
|
||||
this.setState({
|
||||
sameImg: !this.props.account ? false : this.props.account.get('avatar') === this.props.account.get('avatar_static'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleMouseEnter = () => {
|
||||
@@ -43,8 +50,8 @@ class Avatar extends ImmutablePureComponent {
|
||||
className: [_s.default, _s.circle, _s.overflowHidden].join(' '),
|
||||
onMouseEnter: shouldAnimate ? this.handleMouseEnter : undefined,
|
||||
onMouseLeave: shouldAnimate ? this.handleMouseLeave : undefined,
|
||||
src: account.get((hovering || animate) ? 'avatar' : 'avatar_static'),
|
||||
alt: account.get('display_name'),
|
||||
src: !account ? undefined : account.get((hovering || animate) ? 'avatar' : 'avatar_static'),
|
||||
alt: !account ? undefined : account.get('display_name'),
|
||||
style: {
|
||||
width: `${size}px`,
|
||||
height: `${size}px`,
|
||||
|
||||
@@ -36,6 +36,7 @@ export default class Button extends PureComponent {
|
||||
narrow: PropTypes.bool,
|
||||
underlineOnHover: PropTypes.bool,
|
||||
radiusSmall: PropTypes.bool,
|
||||
noClasses: PropTypes.bool,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
@@ -50,6 +51,8 @@ export default class Button extends PureComponent {
|
||||
}
|
||||
|
||||
setRef = (c) => {
|
||||
const { buttonRef } = this.props
|
||||
if (buttonRef) buttonRef(c)
|
||||
this.node = c
|
||||
}
|
||||
|
||||
@@ -76,6 +79,7 @@ export default class Button extends PureComponent {
|
||||
underlineOnHover,
|
||||
narrow,
|
||||
radiusSmall,
|
||||
noClasses,
|
||||
...otherProps
|
||||
} = this.props
|
||||
|
||||
@@ -89,7 +93,7 @@ export default class Button extends PureComponent {
|
||||
) : undefined
|
||||
|
||||
// : todo :
|
||||
const classes = cx(className, {
|
||||
const classes = noClasses ? className : cx(className, {
|
||||
default: 1,
|
||||
noUnderline: 1,
|
||||
font: 1,
|
||||
|
||||
@@ -19,6 +19,7 @@ export default class Input extends PureComponent {
|
||||
title: PropTypes.string,
|
||||
small: PropTypes.bool,
|
||||
readOnly: PropTypes.string,
|
||||
inputRef: PropTypes.func,
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -34,7 +35,8 @@ export default class Input extends PureComponent {
|
||||
onClear,
|
||||
title,
|
||||
small,
|
||||
readOnly
|
||||
readOnly,
|
||||
inputRef
|
||||
} = this.props
|
||||
|
||||
const inputClasses = cx({
|
||||
@@ -75,6 +77,7 @@ export default class Input extends PureComponent {
|
||||
className={inputClasses}
|
||||
type='text'
|
||||
placeholder={placeholder}
|
||||
ref={inputRef}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onKeyUp={onKeyUp}
|
||||
|
||||
@@ -8,10 +8,11 @@ export default class List extends PureComponent {
|
||||
items: PropTypes.array,
|
||||
scrollKey: PropTypes.string,
|
||||
emptyMessage: PropTypes.any,
|
||||
small: PropTypes.bool,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { items, scrollKey, emptyMessage } = this.props
|
||||
const { items, scrollKey, emptyMessage, small } = this.props
|
||||
|
||||
return (
|
||||
<Block>
|
||||
@@ -23,16 +24,16 @@ export default class List extends PureComponent {
|
||||
items.map((item, i) => {
|
||||
return (
|
||||
<ListItem
|
||||
small={small}
|
||||
key={`list-item-${i}`}
|
||||
to={item.to}
|
||||
title={item.title}
|
||||
isLast={items.length - 1 === i}
|
||||
{...item}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ScrollableList>
|
||||
</Block>
|
||||
</Block>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import classNames from 'classnames/bind'
|
||||
import Button from './button'
|
||||
import Icon from './icon'
|
||||
import Text from './text'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
@@ -8,38 +9,52 @@ export default class ListItem extends PureComponent {
|
||||
static propTypes = {
|
||||
isLast: PropTypes.bool,
|
||||
to: PropTypes.string,
|
||||
href: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
small: PropTypes.bool,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { to, title, isLast } = this.props
|
||||
const { title, isLast, to, href, onClick, small } = this.props
|
||||
|
||||
const containerClasses = cx({
|
||||
default: 1,
|
||||
cursorPointer: 1,
|
||||
noUnderline: 1,
|
||||
px15: 1,
|
||||
py15: 1,
|
||||
px15: !small,
|
||||
py15: !small,
|
||||
px10: small,
|
||||
py10: small,
|
||||
flexRow: 1,
|
||||
alignItemsCenter: 1,
|
||||
width100PC: 1,
|
||||
backgroundSubtle_onHover: 1,
|
||||
borderColorSecondary: !isLast,
|
||||
borderBottom1PX: !isLast,
|
||||
})
|
||||
|
||||
const textSize = small ? 'small' : 'normal'
|
||||
|
||||
return (
|
||||
<NavLink to={to} className={containerClasses} >
|
||||
<span className={[_s.default, _s.text, _s.colorPrimary, _s.fontSize14PX].join(' ')}>
|
||||
<Button
|
||||
to={to}
|
||||
href={href}
|
||||
onClick={onClick}
|
||||
className={containerClasses}
|
||||
noClasses
|
||||
>
|
||||
<Text color='primary' size={textSize}>
|
||||
{title}
|
||||
</span>
|
||||
</Text>
|
||||
|
||||
<Icon
|
||||
id='angle-right'
|
||||
width='10px'
|
||||
height='10px'
|
||||
className={[_s.marginLeftAuto, _s.fillColorBlack].join(' ')}
|
||||
/>
|
||||
</NavLink>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { shortNumberFormat } from '../../utils/numbers';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
count: state.getIn(['notifications', 'unread']),
|
||||
});
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps)
|
||||
class NotificationCounter extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
count: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { count } = this.props;
|
||||
|
||||
if (count < 1) return null;
|
||||
|
||||
return (
|
||||
<span className='notification-counter'>{shortNumberFormat(count)}</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,6 @@ const mapStateToProps = state => ({
|
||||
isModalOpen: state.get('modal').modalType === 'ACTIONS',
|
||||
popoverPlacement: state.getIn(['popover', 'placement']),
|
||||
openPopoverType: state.getIn(['popover', 'popoverType']),
|
||||
openedViaKeyboard: state.getIn(['popover', 'keyboard']),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, { status, items }) => ({
|
||||
@@ -55,9 +54,9 @@ class PopoverBase extends ImmutablePureComponent {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
position: PropTypes.string,
|
||||
openPopoverType: PropTypes.number,
|
||||
openedViaKeyboard: PropTypes.bool,
|
||||
visible: PropTypes.bool,
|
||||
targetRef: PropTypes.node,
|
||||
innerRef: PropTypes.node,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
@@ -137,8 +136,8 @@ class PopoverBase extends ImmutablePureComponent {
|
||||
disabled,
|
||||
position,
|
||||
openPopoverType,
|
||||
openedViaKeyboard,
|
||||
targetRef,
|
||||
innerRef,
|
||||
} = this.props
|
||||
const open = this.state.id === openPopoverType
|
||||
|
||||
@@ -155,13 +154,10 @@ class PopoverBase extends ImmutablePureComponent {
|
||||
referenceElement={targetRef}
|
||||
>
|
||||
{({ ref, style, placement, arrowProps }) => (
|
||||
<div ref={ref} style={style} data-placement={placement}>
|
||||
<div ref={ref} style={style} data-placement={placement} className={[_s.my5, _s.boxShadow2].join(' ')}>
|
||||
<div ref={arrowProps.ref} style={arrowProps.style} />
|
||||
<div data-popover='true' onKeyDown={this.handleKeyDown} className={containerClasses}>
|
||||
{children}
|
||||
{ /* <div show={open} placement={popoverPlacement} target={this.findTarget}>
|
||||
<PopoverMenu items={items} onClose={this.handleClose} openedViaKeyboard={openedViaKeyboard} />
|
||||
</div> */}
|
||||
<div ref={innerRef} data-popover='true' onKeyDown={this.handleKeyDown} className={containerClasses}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -19,7 +19,7 @@ const POPOVER_COMPONENTS = {
|
||||
CONTENT_WARNING: () => Promise.resolve({ default: ContentWarningPopover }),
|
||||
DATE_PICKER: () => Promise.resolve({ default: DatePickerPopover }),
|
||||
GROUP_INFO: () => GroupInfoPopover,
|
||||
PROFILE_OPTIONS: () => ProfileOptionsPopover,
|
||||
PROFILE_OPTIONS: () => Promise.resolve({ default: ProfileOptionsPopover }),
|
||||
SEARCH: () => Promise.resolve({ default: SearchPopover }),
|
||||
SIDEBAR_MORE: () => Promise.resolve({ default: SidebarMorePopover }),
|
||||
STATUS_OPTIONS: () => Promise.resolve({ default: StatusOptionsPopover }),
|
||||
@@ -60,7 +60,6 @@ class PopoverRoot extends PureComponent {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
style: PropTypes.object,
|
||||
placement: PropTypes.string,
|
||||
openedViaKeyboard: PropTypes.bool,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
@@ -73,25 +72,23 @@ class PopoverRoot extends PureComponent {
|
||||
}
|
||||
|
||||
handleDocumentClick = e => {
|
||||
// if (this.node && !this.node.contains(e.target)) {
|
||||
// this.props.onClose()
|
||||
// }
|
||||
if (this.node && !this.node.contains(e.target)) {
|
||||
this.props.onClose()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// document.addEventListener('click', this.handleDocumentClick, false)
|
||||
// document.addEventListener('keydown', this.handleKeyDown, false)
|
||||
// document.addEventListener('touchend', this.handleDocumentClick, listenerOptions)
|
||||
document.addEventListener('click', this.handleDocumentClick, false)
|
||||
document.addEventListener('keydown', this.handleKeyDown, false)
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions)
|
||||
|
||||
// if (this.focusedItem && this.props.openedViaKeyboard) this.focusedItem.focus()
|
||||
|
||||
// this.setState({ mounted: true })
|
||||
this.setState({ mounted: true })
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// document.removeEventListener('click', this.handleDocumentClick, false)
|
||||
// document.removeEventListener('keydown', this.handleKeyDown, false)
|
||||
// document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions)
|
||||
document.removeEventListener('click', this.handleDocumentClick, false)
|
||||
document.removeEventListener('keydown', this.handleKeyDown, false)
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions)
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
@@ -165,12 +162,10 @@ class PopoverRoot extends PureComponent {
|
||||
const { mounted } = this.state
|
||||
const visible = !!type
|
||||
|
||||
console.log("popover root - type, visible:", type, visible, props, POPOVER_COMPONENTS[type])
|
||||
|
||||
return (
|
||||
<PopoverBase
|
||||
visible={visible}
|
||||
ref={this.setRef}
|
||||
innerRef={this.setRef}
|
||||
{...props}
|
||||
>
|
||||
{
|
||||
|
||||
@@ -1,11 +1,245 @@
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
|
||||
import {
|
||||
followAccount,
|
||||
unfollowAccount,
|
||||
blockAccount,
|
||||
unblockAccount,
|
||||
unmuteAccount,
|
||||
pinAccount,
|
||||
unpinAccount,
|
||||
} from '../../actions/accounts'
|
||||
import {
|
||||
mentionCompose,
|
||||
} from '../../actions/compose'
|
||||
import { initMuteModal } from '../../actions/mutes'
|
||||
import { initReport } from '../../actions/reports'
|
||||
import { openModal } from '../../actions/modal'
|
||||
import { blockDomain, unblockDomain } from '../../actions/domain_blocks'
|
||||
import { unfollowModal, autoPlayGif, me, isStaff } from '../../initial_state'
|
||||
import { makeGetAccount } from '../../selectors'
|
||||
import PopoverLayout from './popover_layout'
|
||||
import Text from '../text'
|
||||
import List from '../list'
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||
blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
|
||||
account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
|
||||
mention: { id: 'account.mention', defaultMessage: 'Mention' },
|
||||
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
|
||||
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
||||
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
|
||||
report: { id: 'account.report', defaultMessage: 'Report @{name}' },
|
||||
share: { id: 'account.share', defaultMessage: 'Share @{name}\'s profile' },
|
||||
media: { id: 'account.media', defaultMessage: 'Media' },
|
||||
blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
hideReposts: { id: 'account.hide_reblogs', defaultMessage: 'Hide reposts from @{name}' },
|
||||
showReposts: { id: 'account.show_reblogs', defaultMessage: 'Show reposts from @{name}' },
|
||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
|
||||
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
|
||||
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
||||
accountFollowsYou: { id: 'account.follows_you', defaultMessage: 'Follows you' },
|
||||
accountBlocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
|
||||
accountMuted: { id: 'account.muted', defaultMessage: 'Muted' },
|
||||
domainBlocked: { id: 'account.domain_blocked', defaultMessage: 'Domain hidden' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, { account }) => ({
|
||||
account: getAccount(state, !!account ? account.get('id') : -1),
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onFollow (account) {
|
||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
||||
if (unfollowModal) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.unfollowConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
}));
|
||||
} else {
|
||||
dispatch(unfollowAccount(account.get('id')));
|
||||
}
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onBlock (account) {
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
dispatch(unblockAccount(account.get('id')));
|
||||
} else {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.get('id'))),
|
||||
secondary: intl.formatMessage(messages.blockAndReport),
|
||||
onSecondary: () => {
|
||||
dispatch(blockAccount(account.get('id')));
|
||||
dispatch(initReport(account));
|
||||
},
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
onMention (account, router) {
|
||||
dispatch(mentionCompose(account, router));
|
||||
},
|
||||
|
||||
onRepostToggle (account) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
dispatch(followAccount(account.get('id'), false));
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id'), true));
|
||||
}
|
||||
},
|
||||
|
||||
onEndorseToggle (account) {
|
||||
if (account.getIn(['relationship', 'endorsed'])) {
|
||||
dispatch(unpinAccount(account.get('id')));
|
||||
} else {
|
||||
dispatch(pinAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onReport (account) {
|
||||
dispatch(initReport(account));
|
||||
},
|
||||
|
||||
onMute (account) {
|
||||
if (account.getIn(['relationship', 'muting'])) {
|
||||
dispatch(unmuteAccount(account.get('id')));
|
||||
} else {
|
||||
dispatch(initMuteModal(account));
|
||||
}
|
||||
},
|
||||
|
||||
onBlockDomain (domain) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
onConfirm: () => dispatch(blockDomain(domain)),
|
||||
}));
|
||||
},
|
||||
|
||||
onUnblockDomain (domain) {
|
||||
dispatch(unblockDomain(domain));
|
||||
},
|
||||
|
||||
onAddToList(account){
|
||||
dispatch(openModal('LIST_ADDER', {
|
||||
accountId: account.get('id'),
|
||||
}));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
export default
|
||||
@injectIntl
|
||||
@connect(makeMapStateToProps, mapDispatchToProps)
|
||||
class ProfileOptionsPopover extends PureComponent {
|
||||
|
||||
makeMenu() {
|
||||
const { account, intl, domain } = this.props;
|
||||
|
||||
let menu = [];
|
||||
|
||||
if (!account) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ('share' in navigator) {
|
||||
menu.push({ title: intl.formatMessage(messages.share, { name: account.get('username') }), onClick: this.handleShare });
|
||||
}
|
||||
|
||||
if (account.get('id') === me) {
|
||||
menu.push({ title: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });
|
||||
menu.push({ title: intl.formatMessage(messages.preferences), href: '/settings/preferences' });
|
||||
menu.push({ title: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
|
||||
menu.push({ title: intl.formatMessage(messages.mutes), to: '/mutes' });
|
||||
menu.push({ title: intl.formatMessage(messages.blocks), to: '/blocks' });
|
||||
menu.push({ title: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });
|
||||
} else {
|
||||
menu.push({ title: intl.formatMessage(messages.mention, { name: account.get('acct') }), onClick: this.props.onMention });
|
||||
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
menu.push({ title: intl.formatMessage(messages.hideReposts, { name: account.get('username') }), onClick: this.props.onRepostToggle });
|
||||
} else {
|
||||
menu.push({ title: intl.formatMessage(messages.showReposts, { name: account.get('username') }), onClick: this.props.onRepostToggle });
|
||||
}
|
||||
|
||||
menu.push({ title: intl.formatMessage(messages.add_or_remove_from_list), onClick: this.props.onAddToList });
|
||||
menu.push({ title: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), onClick: this.props.onEndorseToggle });
|
||||
}
|
||||
|
||||
if (account.getIn(['relationship', 'muting'])) {
|
||||
menu.push({ title: intl.formatMessage(messages.unmute, { name: account.get('username') }), onClick: this.props.onMute });
|
||||
} else {
|
||||
menu.push({ title: intl.formatMessage(messages.mute, { name: account.get('username') }), onClick: this.props.onMute });
|
||||
}
|
||||
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
menu.push({ title: intl.formatMessage(messages.unblock, { name: account.get('username') }), onClick: this.props.onBlock });
|
||||
} else {
|
||||
menu.push({ title: intl.formatMessage(messages.block, { name: account.get('username') }), onClick: this.props.onBlock });
|
||||
}
|
||||
|
||||
menu.push({ title: intl.formatMessage(messages.report, { name: account.get('username') }), onClick: this.props.onReport });
|
||||
}
|
||||
|
||||
if (account.get('acct') !== account.get('username')) {
|
||||
const domain = account.get('acct').split('@')[1];
|
||||
|
||||
if (account.getIn(['relationship', 'domain_blocking'])) {
|
||||
menu.push({ title: intl.formatMessage(messages.unblockDomain, { domain }), onClick: this.props.onUnblockDomain });
|
||||
} else {
|
||||
menu.push({ title: intl.formatMessage(messages.blockDomain, { domain }), onClick: this.props.onBlockDomain });
|
||||
}
|
||||
}
|
||||
|
||||
if (account.get('id') !== me && isStaff) {
|
||||
menu.push({ title: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${account.get('id')}` });
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
export default class UserInfoPopover extends PureComponent {
|
||||
render() {
|
||||
const listItems = this.makeMenu()
|
||||
|
||||
return (
|
||||
<PopoverLayout>
|
||||
<Text>testing</Text>
|
||||
<List
|
||||
scrollKey='profile_options'
|
||||
items={listItems}
|
||||
small
|
||||
/>
|
||||
</PopoverLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
import PopoverLayout from './popover_layout'
|
||||
import List from '../list'
|
||||
|
||||
export default class SidebarMorePopover extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{ /* */ }
|
||||
</div>
|
||||
<PopoverLayout>
|
||||
<List
|
||||
scrollKey='profile_options'
|
||||
items={[
|
||||
{
|
||||
title: 'Help',
|
||||
href: 'https://help.gab.com',
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
href: '/settings',
|
||||
},
|
||||
{
|
||||
title: 'Log Out',
|
||||
href: '/auth/log_out',
|
||||
},
|
||||
]}
|
||||
small
|
||||
/>
|
||||
</PopoverLayout>
|
||||
)
|
||||
}
|
||||
}
|
||||
278
app/javascript/gabsocial/components/profile_header.js
Normal file
278
app/javascript/gabsocial/components/profile_header.js
Normal file
@@ -0,0 +1,278 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
|
||||
import classNames from 'classnames/bind'
|
||||
import {
|
||||
followAccount,
|
||||
unfollowAccount,
|
||||
blockAccount,
|
||||
unblockAccount,
|
||||
} from '../actions/accounts'
|
||||
import { openPopover, closePopover } from '../actions/popover'
|
||||
import { initReport } from '../actions/reports'
|
||||
import { openModal } from '../actions/modal'
|
||||
import { unfollowModal } from '../initial_state'
|
||||
import Avatar from './avatar'
|
||||
import Image from './image'
|
||||
import Text from './text'
|
||||
import Button from './button'
|
||||
import DisplayName from './display_name'
|
||||
import TabBar from './tab_bar'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
const messages = defineMessages({
|
||||
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
||||
follows: { id: 'account.follows', defaultMessage: 'Follows' },
|
||||
profile: { id: 'account.profile', defaultMessage: 'Profile' },
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
openProfileOptionsPopover(props) {
|
||||
console.log("props:", props)
|
||||
dispatch(openPopover('PROFILE_OPTIONS', props))
|
||||
},
|
||||
|
||||
onFollow (account) {
|
||||
if (account.getIn(['relationship', 'following']) || account.getIn(['relationship', 'requested'])) {
|
||||
if (unfollowModal) {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.unfollowConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
}));
|
||||
} else {
|
||||
dispatch(unfollowAccount(account.get('id')));
|
||||
}
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id')));
|
||||
}
|
||||
},
|
||||
|
||||
onBlock (account) {
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
dispatch(unblockAccount(account.get('id')));
|
||||
} else {
|
||||
dispatch(openModal('CONFIRM', {
|
||||
message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockConfirm),
|
||||
onConfirm: () => dispatch(blockAccount(account.get('id'))),
|
||||
secondary: intl.formatMessage(messages.blockAndReport),
|
||||
onSecondary: () => {
|
||||
dispatch(blockAccount(account.get('id')));
|
||||
dispatch(initReport(account));
|
||||
},
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
onRepostToggle (account) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
dispatch(followAccount(account.get('id'), false));
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id'), true));
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default
|
||||
@connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class ProfileHeader extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
openProfileOptionsPopover: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
handleOpenMore = () => {
|
||||
const { openProfileOptionsPopover, account } = this.props
|
||||
openProfileOptionsPopover({
|
||||
targetRef: this.openMoreNode,
|
||||
position: 'top',
|
||||
account: this.props.account,
|
||||
})
|
||||
}
|
||||
|
||||
handleStartChat = () => {
|
||||
|
||||
}
|
||||
|
||||
handleFollow = () => {
|
||||
|
||||
}
|
||||
|
||||
makeInfo() {
|
||||
const { account, intl } = this.props;
|
||||
|
||||
let 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;
|
||||
};
|
||||
|
||||
getActionBtn() {
|
||||
const { account, intl } = this.props;
|
||||
|
||||
let actionBtn = null;
|
||||
|
||||
if (!account || !me) return actionBtn;
|
||||
|
||||
if (me !== account.get('id')) {
|
||||
if (!account.get('relationship')) { // Wait until the relationship is loaded
|
||||
//
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.requested)} onClick={this.props.onFollow} />;
|
||||
} else if (!account.getIn(['relationship', 'blocking'])) {
|
||||
actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames('logo-button', { 'button--destructive': account.getIn(['relationship', 'following']) })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} />;
|
||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
||||
actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />;
|
||||
}
|
||||
}
|
||||
|
||||
return actionBtn
|
||||
}
|
||||
|
||||
setOpenMoreNodeRef = (n) => {
|
||||
this.openMoreNode = n
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account, intl } = this.props
|
||||
|
||||
const tabs = !account ? null : [
|
||||
{
|
||||
to: `/${account.get('acct')}`,
|
||||
title: 'Timeline',
|
||||
},
|
||||
{
|
||||
to: `/${account.get('acct')}/comments`,
|
||||
title: 'Comments',
|
||||
},
|
||||
{
|
||||
to: `/${account.get('acct')}/media`,
|
||||
title: 'Media',
|
||||
},
|
||||
{
|
||||
to: '',
|
||||
title: 'More',
|
||||
},
|
||||
]
|
||||
|
||||
const headerSrc = !!account ? account.get('header') : ''
|
||||
const headerMissing = headerSrc.indexOf('/headers/original/missing.png') > -1 || !headerSrc
|
||||
|
||||
const avatarContainerClasses = cx({
|
||||
circle: 1,
|
||||
marginTopNeg75PX: !headerMissing,
|
||||
borderColorWhite: 1,
|
||||
border2PX: 1,
|
||||
})
|
||||
|
||||
const avatarSize = headerMissing ? '75' : '150'
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.z1, _s.width100PC].join(' ')}>
|
||||
|
||||
{
|
||||
!headerMissing &&
|
||||
<div className={[_s.default, _s.height350PX, _s.width100PC, _s.radiusSmall, _s.overflowHidden].join(' ')}>
|
||||
<Image
|
||||
className={_s.height350PX}
|
||||
src={headerSrc}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.borderBottom1PX, _s.borderColorSecondary, _s.width100PC].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.px15].join(' ')}>
|
||||
<div className={avatarContainerClasses}>
|
||||
<Avatar size={avatarSize} account={account} />
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.px15, _s.py10].join(' ')}>
|
||||
<DisplayName account={account} multiline large />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.borderBottom1PX, _s.borderColorSecondary, _s.mt5, _s.height53PX].join(' ')}>
|
||||
<div className={[_s.default].join(' ')}>
|
||||
<TabBar tabs={tabs} large />
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.marginLeftAuto, _s.py5].join(' ')}>
|
||||
<div ref={this.setOpenMoreNodeRef}>
|
||||
<Button
|
||||
outline
|
||||
icon='ellipsis'
|
||||
iconWidth='18px'
|
||||
iconHeight='18px'
|
||||
iconClassName={_s.fillColorBrand}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||
onClick={this.handleOpenMore}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
outline
|
||||
icon='chat'
|
||||
iconWidth='18px'
|
||||
iconHeight='18px'
|
||||
iconClassName={_s.fillColorBrand}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||
onClick={this.handleStartChat}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter].join(' ')}
|
||||
onClick={this.handleFollow}
|
||||
>
|
||||
<span className={[_s.px15].join(' ')}>
|
||||
<Text
|
||||
color='white'
|
||||
weight='bold'
|
||||
size='medium'
|
||||
className={[_s.px15].join(' ')}
|
||||
>
|
||||
Follow
|
||||
</Text>
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,18 +43,19 @@ class Search extends PureComponent {
|
||||
value: PropTypes.string.isRequired,
|
||||
submitted: PropTypes.bool,
|
||||
onShow: PropTypes.func.isRequired,
|
||||
openInRoute: PropTypes.bool,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onKeyUp: PropTypes.func.isRequired,
|
||||
handleSubmit: PropTypes.func,
|
||||
withOverlay: PropTypes.bool,
|
||||
handleClear: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
expanded: false,
|
||||
}
|
||||
|
||||
textbox = React.createRef()
|
||||
|
||||
handleChange = (e) => {
|
||||
this.props.onChange(e.target.value)
|
||||
}
|
||||
@@ -68,8 +69,31 @@ class Search extends PureComponent {
|
||||
this.setState({ expanded: false })
|
||||
}
|
||||
|
||||
handleKeyUp = (e) => {
|
||||
const { value } = this.props
|
||||
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
|
||||
this.props.onSubmit();
|
||||
this.context.router.history.push(`/search?q=${value}`);
|
||||
|
||||
} else if (e.key === 'Escape') {
|
||||
this.textbox.blur()
|
||||
}
|
||||
}
|
||||
|
||||
setTextbox = n => {
|
||||
this.textbox = n
|
||||
}
|
||||
|
||||
render() {
|
||||
const { value, submitted, onKeyUp, handleClear, handleSubmit, withOverlay } = this.props
|
||||
const {
|
||||
value,
|
||||
submitted,
|
||||
handleClear,
|
||||
withOverlay
|
||||
} = this.props
|
||||
const { expanded } = this.state
|
||||
|
||||
const hasValue = value ? value.length > 0 || submitted : 0
|
||||
@@ -79,10 +103,11 @@ class Search extends PureComponent {
|
||||
<Input
|
||||
hasClear
|
||||
value={value}
|
||||
inputRef={this.setTextbox}
|
||||
prependIcon='search'
|
||||
placeholder='Search on Gab...'
|
||||
onChange={this.handleChange}
|
||||
onKeyUp={onKeyUp}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
onClear={handleClear}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { injectIntl, defineMessages } from 'react-intl'
|
||||
import Button from './button'
|
||||
import { closeSidebar } from '../actions/sidebar'
|
||||
import { openModal } from '../actions/modal'
|
||||
import { openPopover } from '../actions/popover'
|
||||
import { me } from '../initial_state'
|
||||
import { makeGetAccount } from '../selectors'
|
||||
import SidebarSectionTitle from './sidebar_section_title'
|
||||
@@ -37,6 +38,8 @@ const mapStateToProps = state => {
|
||||
return {
|
||||
account: getAccount(state, me),
|
||||
sidebarOpen: state.get('sidebar').sidebarOpen,
|
||||
notificationCount: state.getIn(['notifications', 'unread']),
|
||||
homeItemsQueueCount: state.getIn(['timelines', 'home', 'totalQueuedItemsCount']),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +47,9 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
onClose() {
|
||||
dispatch(closeSidebar())
|
||||
},
|
||||
openSidebarMorePopover(props) {
|
||||
dispatch(openPopover('SIDEBAR_MORE', props))
|
||||
},
|
||||
onOpenComposeModal() {
|
||||
dispatch(openModal('COMPOSE'))
|
||||
},
|
||||
@@ -60,6 +66,9 @@ class Sidebar extends ImmutablePureComponent {
|
||||
sidebarOpen: PropTypes.bool,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onOpenComposeModal: PropTypes.func.isRequired,
|
||||
openSidebarMorePopover: PropTypes.func.isRequired,
|
||||
notificationCount: PropTypes.number.isRequired,
|
||||
homeItemsQueueCount: PropTypes.number.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
@@ -90,12 +99,23 @@ class Sidebar extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
handleOpenComposeModal = () => {
|
||||
console.log("handleOpenComposeModal")
|
||||
this.props.onOpenComposeModal()
|
||||
}
|
||||
|
||||
handleOpenSidebarMorePopover =() => {
|
||||
console.log("handleOpenSidebarMorePopover")
|
||||
this.props.openSidebarMorePopover({
|
||||
targetRef: this.moreBtnRef,
|
||||
position: 'top',
|
||||
})
|
||||
}
|
||||
|
||||
setMoreButtonRef = n => {
|
||||
this.moreBtnRef = n
|
||||
}
|
||||
|
||||
render() {
|
||||
const { sidebarOpen, intl, account } = this.props
|
||||
const { sidebarOpen, intl, account, notificationCount, homeItemsQueueCount } = this.props
|
||||
const { moreOpen } = this.state
|
||||
|
||||
// : todo :
|
||||
@@ -112,19 +132,20 @@ class Sidebar extends ImmutablePureComponent {
|
||||
title: 'Home',
|
||||
icon: 'home',
|
||||
to: '/',
|
||||
count: 124,
|
||||
count: homeItemsQueueCount,
|
||||
},
|
||||
{
|
||||
title: 'Notifications',
|
||||
icon: 'notifications',
|
||||
to: '/notifications',
|
||||
count: 40,
|
||||
},
|
||||
{
|
||||
title: 'Search',
|
||||
icon: 'search-alt',
|
||||
to: '/search',
|
||||
count: notificationCount,
|
||||
},
|
||||
// : todo : show only when search on top is not visible
|
||||
// {
|
||||
// title: 'Search',
|
||||
// icon: 'search-alt',
|
||||
// to: '/search',
|
||||
// },
|
||||
{
|
||||
title: 'Groups',
|
||||
icon: 'group',
|
||||
@@ -138,17 +159,17 @@ class Sidebar extends ImmutablePureComponent {
|
||||
{
|
||||
title: 'Chat',
|
||||
icon: 'chat',
|
||||
to: '',
|
||||
// href: 'https://chat.gab.com',
|
||||
href: 'https://chat.gab.com',
|
||||
},
|
||||
{
|
||||
title: 'More',
|
||||
icon: 'more',
|
||||
to: '/',
|
||||
onClick: this.handleOpenSidebarMorePopover,
|
||||
buttonRef: this.setMoreButtonRef
|
||||
},
|
||||
]
|
||||
|
||||
// more:
|
||||
// more modal:
|
||||
// settings/preferences
|
||||
// help
|
||||
// logout
|
||||
@@ -172,26 +193,22 @@ class Sidebar extends ImmutablePureComponent {
|
||||
{
|
||||
title: 'Apps',
|
||||
icon: 'apps',
|
||||
to: '',
|
||||
// href: 'https://apps.gab.com',
|
||||
href: 'https://apps.gab.com',
|
||||
},
|
||||
{
|
||||
title: 'Shop',
|
||||
icon: 'shop',
|
||||
to: '',
|
||||
// href: 'https://shop.dissenter.com',
|
||||
href: 'https://shop.dissenter.com',
|
||||
},
|
||||
{
|
||||
title: 'Trends',
|
||||
icon: 'trends',
|
||||
to: '',
|
||||
// href: 'https://trends.gab.com',
|
||||
href: 'https://trends.gab.com',
|
||||
},
|
||||
{
|
||||
title: 'Dissenter',
|
||||
icon: 'dissenter',
|
||||
to: '',
|
||||
// href: 'https://dissenter.com',
|
||||
href: 'https://dissenter.com',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -199,7 +216,7 @@ class Sidebar extends ImmutablePureComponent {
|
||||
<header role='banner' className={[_s.default, _s.flexGrow1, _s.z3, _s.alignItemsEnd].join(' ')}>
|
||||
<div className={[_s.default, _s.width240PX].join(' ')}>
|
||||
<div className={[_s.default, _s.positionFixed, _s.top0, _s.height100PC].join(' ')}>
|
||||
<div className={[_s.default, _s.height100PC, _s.width240PX, _s.pr15, _s.my10].join(' ')}>
|
||||
<div className={[_s.default, _s.height100PC, _s.width240PX, _s.pr15, _s.py10, _s.overflowYScroll].join(' ')}>
|
||||
|
||||
<SidebarHeader />
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import classNames from 'classnames/bind'
|
||||
import Button from './button'
|
||||
import Icon from './icon'
|
||||
import Text from './text'
|
||||
|
||||
const cx = classNames.bind(_s)
|
||||
|
||||
export default class SidebarSectionItem extends PureComponent {
|
||||
static propTypes = {
|
||||
to: PropTypes.string,
|
||||
href: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
active: PropTypes.bool,
|
||||
icon: PropTypes.string,
|
||||
image: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
me: PropTypes.bool,
|
||||
suffix: PropTypes.node,
|
||||
buttonRef: PropTypes.func,
|
||||
}
|
||||
|
||||
state = {
|
||||
@@ -30,7 +31,18 @@ export default class SidebarSectionItem extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { to, active, icon, image, title, me, count } = this.props
|
||||
const {
|
||||
to,
|
||||
active,
|
||||
icon,
|
||||
image,
|
||||
title,
|
||||
me,
|
||||
count,
|
||||
onClick,
|
||||
href,
|
||||
buttonRef
|
||||
} = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
const iconSize = '16px'
|
||||
@@ -49,6 +61,7 @@ export default class SidebarSectionItem extends PureComponent {
|
||||
// border1PX: shouldShowActive,
|
||||
// borderColorSecondary: shouldShowActive,
|
||||
backgroundSubtle2: shouldShowActive,
|
||||
backgroundTransparent: 1,
|
||||
})
|
||||
|
||||
const textClasses = cx({
|
||||
@@ -63,7 +76,7 @@ export default class SidebarSectionItem extends PureComponent {
|
||||
|
||||
const iconClasses = cx({
|
||||
fillColorBlack: shouldShowActive,
|
||||
fillcolorSecondary: !hovering && !active,
|
||||
fillColorSecondary: !hovering && !active,
|
||||
})
|
||||
|
||||
const countClasses = cx({
|
||||
@@ -82,11 +95,15 @@ export default class SidebarSectionItem extends PureComponent {
|
||||
})
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
<Button
|
||||
to={to}
|
||||
href={href}
|
||||
onClick={onClick}
|
||||
noClasses
|
||||
buttonRef={buttonRef}
|
||||
onMouseEnter={() => this.handleOnMouseEnter()}
|
||||
onMouseLeave={() => this.handleOnMouseLeave()}
|
||||
className={[_s.default, _s.noUnderline, _s.cursorPointer, _s.width100PC, _s.alignItemsStart].join(' ')}
|
||||
className={[_s.default, _s.noUnderline, _s.cursorPointer, _s.width100PC, _s.alignItemsStart, _s.backgroundTransparent].join(' ')}
|
||||
>
|
||||
<div className={containerClasses}>
|
||||
<div className={[_s.default]}>
|
||||
@@ -109,7 +126,7 @@ export default class SidebarSectionItem extends PureComponent {
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</NavLink>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ class Status extends ImmutablePureComponent {
|
||||
prepend = (
|
||||
<div className='status__prepend'>
|
||||
<div className='status__prepend-icon-wrapper'>
|
||||
<Icon id='retweet' className='status__prepend-icon' fixedWidth />
|
||||
<Icon id='repost' className='status__prepend-icon' fixedWidth />
|
||||
</div>
|
||||
{/*<FormattedMessage
|
||||
id='status.reposted_by'
|
||||
@@ -382,7 +382,7 @@ class Status extends ImmutablePureComponent {
|
||||
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||
const video = status.getIn(['media_attachments', 0]);
|
||||
|
||||
console.log("VIDEO HERE")
|
||||
// console.log("VIDEO HERE")
|
||||
|
||||
media = (
|
||||
<Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer}>
|
||||
@@ -435,6 +435,10 @@ class Status extends ImmutablePureComponent {
|
||||
)
|
||||
}
|
||||
|
||||
// console.log("da status:", status)
|
||||
let quotedStatus = status.get('quotedStatus');
|
||||
// console.log("quotedStatus:", quotedStatus)
|
||||
|
||||
const handlers = this.props.muted ? {} : {
|
||||
reply: this.handleHotkeyReply,
|
||||
favorite: this.handleHotkeyFavorite,
|
||||
@@ -509,9 +513,9 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
<StatusActionBar status={status} account={account} {...other} />
|
||||
|
||||
{ /* <div className={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px15, _s.mb10].join(' ')}>
|
||||
<ComposeFormContainer statusId={status.get('id')} shouldCondense />
|
||||
</div> */ }
|
||||
<div className={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px15, _s.mb10].join(' ')}>
|
||||
{/*<ComposeFormContainer replyToId={status.get('id')} shouldCondense />*/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@ class StatusContent extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
reblogContent: PropTypes.string,
|
||||
reblogStatus: PropTypes.string,
|
||||
expanded: PropTypes.bool,
|
||||
onExpandedToggle: PropTypes.func,
|
||||
onClick: PropTypes.func,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Toggle from 'react-toggle';
|
||||
import Toggle from 'react-toggle'
|
||||
|
||||
export default class ToggleSwitch extends PureComponent {
|
||||
render() {
|
||||
return <Toggle {...this.props} />
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user