Progress
This commit is contained in:
@@ -236,7 +236,6 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
outlineNone: 1,
|
||||
lineHeight125: 1,
|
||||
colorPrimary: 1,
|
||||
height100PC: small,
|
||||
width100PC: !small,
|
||||
pt15: !small,
|
||||
px15: !small,
|
||||
@@ -253,7 +252,6 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
default: 1,
|
||||
maxWidth100PC: 1,
|
||||
flexGrow1: small,
|
||||
height100PC: small,
|
||||
justifyContentCenter: small,
|
||||
})
|
||||
|
||||
@@ -261,7 +259,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={textareaContainerClasses}>
|
||||
<Textarea
|
||||
{/*<Textarea
|
||||
inputRef={this.setTextbox}
|
||||
className={textareaClasses}
|
||||
disabled={disabled}
|
||||
@@ -275,9 +273,9 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
// onBlur={this.onBlur}
|
||||
// onPaste={this.onPaste}
|
||||
aria-autocomplete='list'
|
||||
/>
|
||||
/>*/}
|
||||
|
||||
{/*<Composer
|
||||
<Composer
|
||||
inputRef={this.setTextbox}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
@@ -290,7 +288,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||
onBlur={this.onBlur}
|
||||
onPaste={this.onPaste}
|
||||
small={small}
|
||||
/>*/}
|
||||
/>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
|
||||
48
app/javascript/gabsocial/components/back_button.js
Normal file
48
app/javascript/gabsocial/components/back_button.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import Button from './button'
|
||||
|
||||
export default class BackButton extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
classNames: PropTypes.string,
|
||||
iconClassName: PropTypes.string,
|
||||
iconSize: PropTypes.string,
|
||||
}
|
||||
|
||||
historyBack = () => {
|
||||
if (window.history && window.history.length === 1) {
|
||||
this.context.router.history.push('/home')
|
||||
} else {
|
||||
this.context.router.history.goBack()
|
||||
}
|
||||
}
|
||||
|
||||
handleBackClick = () => {
|
||||
this.historyBack()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classNames,
|
||||
iconClassName,
|
||||
iconSize,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Button
|
||||
noClasses
|
||||
color='primary'
|
||||
backgroundColor='none'
|
||||
className={classNames || [_s.alignItemsCenter, _s.bgTransparent, _s.mr5, _s.cursorPointer, _s.outlineNone, _s.default, _s.justifyContentCenter].join(' ')}
|
||||
icon='arrow-left'
|
||||
iconSize={iconSize || '24px'}
|
||||
iconClassName={iconClassName || [_s.mr5, _s.fillPrimary].join(' ')}
|
||||
onClick={this.handleBackClick}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import Button from './button'
|
||||
import Comment from './comment'
|
||||
import ScrollableList from './scrollable_list'
|
||||
import Text from './text'
|
||||
import { PureComponent } from 'react';
|
||||
import Dummy from './dummy'
|
||||
|
||||
export default class CommentList extends ImmutablePureComponent {
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class CommentList extends ImmutablePureComponent {
|
||||
const upperLimit = commentsLimited ? 6 : size
|
||||
const max = Math.min(commentsLimited ? 2 : upperLimit, size)
|
||||
|
||||
const Wrapper = !commentsLimited ? ScrollableList : DummyContainer
|
||||
const Wrapper = !commentsLimited ? ScrollableList : Dummy
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -70,10 +70,4 @@ export default class CommentList extends ImmutablePureComponent {
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DummyContainer extends PureComponent {
|
||||
render() {
|
||||
return <div>{this.props.children}</div>
|
||||
}
|
||||
}
|
||||
@@ -201,8 +201,9 @@ class Composer extends PureComponent {
|
||||
pt15: !small,
|
||||
px15: !small,
|
||||
px10: small,
|
||||
pt10: small,
|
||||
pb10: 1,
|
||||
pt5: small,
|
||||
pb5: small,
|
||||
pb10: !small,
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
5
app/javascript/gabsocial/components/dummy.js
Normal file
5
app/javascript/gabsocial/components/dummy.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export default class Dummy extends PureComponent {
|
||||
render() {
|
||||
return <div>{this.props.children}</div>
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ export default class ErrorBoundary extends PureComponent {
|
||||
|
||||
<h1 className={[_s.default, _s.mr15].join(' ')}>
|
||||
<Button href='/' isText aria-label='Gab' className={[_s.default, _s.justifyContentCenter, _s.noSelect, _s.noUnderline, _s.height53PX, _s.cursorPointer, _s.px10, _s.mr15].join(' ')}>
|
||||
<Icon id='gab-logo' className={_s.fillWhite} />
|
||||
<Icon id='logo' className={_s.fillWhite} />
|
||||
</Button>
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@ import { defineMessages, injectIntl } from 'react-intl'
|
||||
import { openPopover, closePopover } from '../actions/popover'
|
||||
import { openModal } from '../actions/modal'
|
||||
import { joinGroup, leaveGroup } from '../actions/groups'
|
||||
import { PLACEHOLDER_MISSING_HEADER_SRC } from '../constants'
|
||||
import {
|
||||
PLACEHOLDER_MISSING_HEADER_SRC,
|
||||
BREAKPOINT_EXTRA_SMALL,
|
||||
} from '../constants'
|
||||
import Responsive from '../features/ui/util/responsive_component'
|
||||
import Button from './button'
|
||||
import Block from './block'
|
||||
import Image from './image'
|
||||
@@ -46,6 +50,7 @@ class GroupHeader extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
group: ImmutablePropTypes.map,
|
||||
children: PropTypes.any,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onToggleMembership: PropTypes.func.isRequired,
|
||||
onOpenGroupOptions: PropTypes.func.isRequired,
|
||||
@@ -67,6 +72,7 @@ class GroupHeader extends ImmutablePureComponent {
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
group,
|
||||
intl,
|
||||
relationships,
|
||||
@@ -90,8 +96,8 @@ class GroupHeader extends ImmutablePureComponent {
|
||||
actionButtonTitle = intl.formatMessage(!isMember ? messages.join : messages.leave)
|
||||
if (isMember) {
|
||||
actionButtonOptions = {
|
||||
backgroundColor: 'tertiary',
|
||||
color: 'primary',
|
||||
backgroundColor: 'danger',
|
||||
color: 'white',
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,25 +105,24 @@ class GroupHeader extends ImmutablePureComponent {
|
||||
// : todo :
|
||||
// {group.get('archived') && <Icon id='lock' title={intl.formatMessage(messages.group_archived)} />}
|
||||
|
||||
// const adminMenu = [
|
||||
// { text: intl.formatMessage(messages.edit), to: `/groups/${group.get('id')}/edit` },
|
||||
// { text: intl.formatMessage(messages.removed_accounts), to: `/groups/${group.get('id')}/removed-accounts` },
|
||||
// ]
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.z1, _s.width100PC, _s.mb15].join(' ')}>
|
||||
<Block>
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
|
||||
{
|
||||
coverSrc && !coverSrcMissing &&
|
||||
<Image className={_s.height350PX} src={coverSrc} alt={title} />
|
||||
}
|
||||
<Responsive max={BREAKPOINT_EXTRA_SMALL}>
|
||||
<div className={[_s.default, _s.boxShadowBlock, _s.bgPrimary].join(' ')}>
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.height53PX, _s.width100PC].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.height100PC, _s.px10].join(' ')}>
|
||||
<TabBar tabs={tabs} />
|
||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.height100PC, _s.mlAuto].join(' ')}>
|
||||
{
|
||||
coverSrc && !coverSrcMissing &&
|
||||
<Image className={_s.height200PX} src={coverSrc} alt={title} />
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.width100PC, _s.px15, _s.mt10, _s.py10].join(' ')}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.borderTop1PX, _s.borderColorSecondary, _s.mt5, _s.pt15, _s.height100PC, _s.px15].join(' ')}>
|
||||
{
|
||||
!!actionButtonTitle &&
|
||||
<Button
|
||||
@@ -126,12 +131,12 @@ class GroupHeader extends ImmutablePureComponent {
|
||||
onClick={this.handleOnToggleMembership}
|
||||
{...actionButtonOptions}
|
||||
>
|
||||
<Text color='inherit' size='small'>
|
||||
<Text color='inherit' size='small' className={_s.px10}>
|
||||
{actionButtonTitle}
|
||||
</Text>
|
||||
</Button>
|
||||
}
|
||||
|
||||
|
||||
<Button
|
||||
radiusSmall
|
||||
color='primary'
|
||||
@@ -142,10 +147,60 @@ class GroupHeader extends ImmutablePureComponent {
|
||||
buttonRef={this.setInfoBtn}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.height100PC, _s.mt15, _s.pt10, _s.px10].join(' ')}>
|
||||
|
||||
<TabBar tabs={tabs} />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Block>
|
||||
</Responsive>
|
||||
|
||||
{ /** desktop */}
|
||||
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
|
||||
<Block>
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
|
||||
{
|
||||
coverSrc && !coverSrcMissing &&
|
||||
<Image className={_s.height350PX} src={coverSrc} alt={title} />
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.height53PX, _s.width100PC].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.height100PC, _s.px10].join(' ')}>
|
||||
<TabBar tabs={tabs} />
|
||||
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.height100PC, _s.mlAuto].join(' ')}>
|
||||
{
|
||||
!!actionButtonTitle &&
|
||||
<Button
|
||||
radiusSmall
|
||||
className={_s.mr5}
|
||||
onClick={this.handleOnToggleMembership}
|
||||
{...actionButtonOptions}
|
||||
>
|
||||
<Text color='inherit' size='small' className={_s.px10}>
|
||||
{actionButtonTitle}
|
||||
</Text>
|
||||
</Button>
|
||||
}
|
||||
|
||||
<Button
|
||||
radiusSmall
|
||||
color='primary'
|
||||
backgroundColor='tertiary'
|
||||
className={_s.mr5}
|
||||
icon='ellipsis'
|
||||
onClick={this.handleOnOpenGroupOptions}
|
||||
buttonRef={this.setInfoBtn}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Block>
|
||||
</Responsive>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ const ICONS = {
|
||||
'error': ErrorIcon,
|
||||
'explore': ExploreIcon,
|
||||
'fullscreen': FullscreenIcon,
|
||||
'gab-logo': GabLogoIcon,
|
||||
'logo': GabLogoIcon,
|
||||
'gif': GifIcon,
|
||||
'globe': GlobeIcon,
|
||||
'group': GroupIcon,
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import Button from './button'
|
||||
import Search from './search'
|
||||
import Text from './text'
|
||||
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component';
|
||||
|
||||
export default class LoggedOutNavigationBar extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
showBackBtn: PropTypes.bool,
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.default, _s.z4, _s.height53PX, _s.width100PC].join(' ')}
|
||||
classNamesXS={[_s.default, _s.z4, _s.height98PX, _s.width100PC].join(' ')}
|
||||
>
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.default, _s.height53PX, _s.flexRow, _s.flexWrap, _s.bgNavigation, _s.alignItemsCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')}
|
||||
classNamesXS={[_s.default, _s.height98PX, _s.flexRow, _s.flexWrap, _s.bgNavigation, _s.alignItemsCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')}
|
||||
>
|
||||
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.default, _s.flexRow, _s.width330PX].join(' ')}
|
||||
classNamesXS={[_s.default, _s.flexRow, _s.width100PC].join(' ')}
|
||||
>
|
||||
|
||||
<Button
|
||||
href='/'
|
||||
color='none'
|
||||
backgroundColor='none'
|
||||
icon='logo'
|
||||
iconClassName={[_s.mr5, _s.fillNavigation].join(' ')}
|
||||
/>
|
||||
|
||||
<div className={[_s.default, _s.flexGrow1, _s.mr10].join(' ')}>
|
||||
<Search />
|
||||
</div>
|
||||
|
||||
</ResponsiveClassesComponent>
|
||||
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.default, _s.flexRow, _s.py5, _s.px10, _s.width330PX, _s.mlAuto].join(' ')}
|
||||
classNamesXS={[_s.default, _s.flexRow, _s.py5, _s.px10, _s.width100PC].join(' ')}
|
||||
>
|
||||
|
||||
<Button
|
||||
isNarrow
|
||||
isOutline
|
||||
color='white'
|
||||
backgroundColor='none'
|
||||
href='/auth/log_in'
|
||||
className={[_s.borderColorWhite, _s.mr5, _s.flexGrow1, _s.alignItemsCenter, _s.justifyContentCenter, _s.py5].join(' ')}
|
||||
>
|
||||
<Text color='inherit' weight='medium' align='center'>
|
||||
Log in
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
isNarrow
|
||||
color='brand'
|
||||
backgroundColor='white'
|
||||
href='/auth/sign_up'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.ml5, _s.flexGrow1, _s.py5].join(' ')}
|
||||
>
|
||||
<Text color='inherit' weight='bold' align='center'>
|
||||
Sign up
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
</ResponsiveClassesComponent>
|
||||
|
||||
</ResponsiveClassesComponent>
|
||||
</ResponsiveClassesComponent>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class NavigationBar extends ImmutablePureComponent {
|
||||
backgroundColor='none'
|
||||
className={[_s.default, _s.justifyContentCenter, _s.noSelect, _s.noUnderline, _s.height53PX, _s.cursorPointer, _s.px10, _s.mr15].join(' ')}
|
||||
>
|
||||
<Icon id='gab-logo' className={_s.fillNavigationBrand} />
|
||||
<Icon id='logo' className={_s.fillNavigationBrand} />
|
||||
</Button>
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { shortNumberFormat } from '../../utils/numbers'
|
||||
import PanelLayout from './panel_layout'
|
||||
import Button from '../button'
|
||||
import Divider from '../divider'
|
||||
import Dummy from '../dummy'
|
||||
import Icon from '../icon'
|
||||
import Text from '../text'
|
||||
import RelativeTimestamp from '../relative_timestamp'
|
||||
@@ -19,7 +20,6 @@ const messages = defineMessages({
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onOpenGroupMembersModal(groupId) {
|
||||
console.log("onOpenGroupMembersModal:", groupId)
|
||||
dispatch(openModal(MODAL_GROUP_MEMBERS, { groupId }))
|
||||
},
|
||||
})
|
||||
@@ -33,6 +33,7 @@ class GroupInfoPanel extends ImmutablePureComponent {
|
||||
group: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onOpenGroupMembersModal: PropTypes.func.isRequired,
|
||||
noPanel: PropTypes.bool,
|
||||
}
|
||||
|
||||
handleOnOpenGroupMembersModal = () => {
|
||||
@@ -40,10 +41,12 @@ class GroupInfoPanel extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, group } = this.props
|
||||
const { intl, group, noPanel } = this.props
|
||||
|
||||
const Wrapper = noPanel ? Dummy : PanelLayout
|
||||
|
||||
return (
|
||||
<PanelLayout title={intl.formatMessage(messages.title)}>
|
||||
<Wrapper title={intl.formatMessage(messages.title)}>
|
||||
{
|
||||
!!group &&
|
||||
<Fragment>
|
||||
@@ -102,7 +105,7 @@ class GroupInfoPanel extends ImmutablePureComponent {
|
||||
</Text>
|
||||
</Fragment>
|
||||
}
|
||||
</PanelLayout>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -38,20 +38,8 @@ class ListsPanel extends ImmutablePureComponent {
|
||||
'lists',
|
||||
]
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
if (!nextProps.isHidden && nextProps.isIntersecting && !prevState.fetched) {
|
||||
return {
|
||||
fetched: true,
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (!prevState.fetched && this.state.fetched) {
|
||||
this.props.onFetchLists()
|
||||
}
|
||||
componentDidMount(prevProps, prevState, snapshot) {
|
||||
this.props.onFetchLists()
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -81,4 +81,4 @@ class MediaGalleryPanel extends ImmutablePureComponent {
|
||||
</PanelLayout>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import PanelLayout from './panel_layout'
|
||||
import Divider from '../divider'
|
||||
import Icon from '../icon'
|
||||
import Text from '../text'
|
||||
import Dummy from '../dummy'
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'about', defaultMessage: 'About' },
|
||||
@@ -39,6 +40,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
static propTypes = {
|
||||
identityProofs: ImmutablePropTypes.list,
|
||||
account: ImmutablePropTypes.map,
|
||||
noPanel: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
@@ -47,7 +49,12 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, account, identityProofs } = this.props
|
||||
const {
|
||||
intl,
|
||||
account,
|
||||
identityProofs,
|
||||
noPanel
|
||||
} = this.props
|
||||
|
||||
if (!account) return null
|
||||
|
||||
@@ -60,8 +67,10 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
const isInvestor = account.get('is_investor')
|
||||
const hasBadges = isPro || isDonor || isInvestor
|
||||
|
||||
const Wrapper = noPanel ? Dummy : PanelLayout
|
||||
|
||||
return (
|
||||
<PanelLayout title={intl.formatMessage(messages.title)}>
|
||||
<Wrapper title={intl.formatMessage(messages.title)}>
|
||||
<div className={[_s.default].join(' ')}>
|
||||
{
|
||||
hasNote &&
|
||||
@@ -166,7 +175,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||
)}
|
||||
|
||||
</div>
|
||||
</PanelLayout>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import { me, favouritesCount } from '../../initial_state'
|
||||
import { shortNumberFormat } from '../../utils/numbers'
|
||||
import PanelLayout from './panel_layout'
|
||||
import UserStat from '../user_stat'
|
||||
import Dummy from '../dummy'
|
||||
import ResponsiveClassesComponent from '../../features/ui/util/responsive_classes_component'
|
||||
|
||||
const messages = defineMessages({
|
||||
gabs: { id: 'account.gabs', defaultMessage: 'Gabs' },
|
||||
@@ -20,32 +22,45 @@ class ProfileStatsPanel extends ImmutablePureComponent {
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
intl: PropTypes.object.isRequired,
|
||||
noPanel: PropTypes.bool,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, account } = this.props
|
||||
const {
|
||||
intl,
|
||||
account,
|
||||
noPanel
|
||||
} = this.props
|
||||
|
||||
if (!account) return null
|
||||
|
||||
const Wrapper = noPanel ? Dummy : PanelLayout
|
||||
|
||||
return (
|
||||
<PanelLayout>
|
||||
<Wrapper>
|
||||
{
|
||||
!!account &&
|
||||
<div className={[_s.default, _s.flexRow].join(' ')}>
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.default, _s.flexRow].join(' ')}
|
||||
classNamesXS={[_s.default, _s.flexRow, _s.mt15, _s.pt10].join(' ')}
|
||||
>
|
||||
<UserStat
|
||||
title={intl.formatMessage(messages.gabs)}
|
||||
value={shortNumberFormat(account.get('statuses_count'))}
|
||||
to={`/${account.get('acct')}`}
|
||||
isCentered={noPanel}
|
||||
/>
|
||||
<UserStat
|
||||
title={intl.formatMessage(messages.follows)}
|
||||
value={shortNumberFormat(account.get('following_count'))}
|
||||
to={`/${account.get('acct')}/following`}
|
||||
isCentered={noPanel}
|
||||
/>
|
||||
<UserStat
|
||||
title={intl.formatMessage(messages.followers)}
|
||||
value={shortNumberFormat(account.get('followers_count'))}
|
||||
to={`/${account.get('acct')}/followers`}
|
||||
isCentered={noPanel}
|
||||
/>
|
||||
{
|
||||
account.get('id') === me &&
|
||||
@@ -53,11 +68,12 @@ class ProfileStatsPanel extends ImmutablePureComponent {
|
||||
title={intl.formatMessage(messages.likes)}
|
||||
value={shortNumberFormat(favouritesCount)}
|
||||
to={`/${account.get('acct')}/likes`}
|
||||
isCentered={noPanel}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</ResponsiveClassesComponent>
|
||||
}
|
||||
</PanelLayout>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
POPOVER_PROFILE_OPTIONS,
|
||||
PLACEHOLDER_MISSING_HEADER_SRC,
|
||||
MODAL_EDIT_PROFILE,
|
||||
BREAKPOINT_EXTRA_SMALL,
|
||||
} from '../constants'
|
||||
import { openModal } from '../actions/modal'
|
||||
import { openPopover } from '../actions/popover'
|
||||
@@ -19,6 +20,7 @@ import Image from './image'
|
||||
import MovedNote from './moved_note'
|
||||
import TabBar from './tab_bar'
|
||||
import Text from './text'
|
||||
import Responsive from '../features/ui/util/responsive_component';
|
||||
|
||||
const messages = defineMessages({
|
||||
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
||||
@@ -51,6 +53,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
children: PropTypes.any,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onEditProfile: PropTypes.func.isRequired,
|
||||
openProfileOptionsPopover: PropTypes.func.isRequired,
|
||||
@@ -87,7 +90,11 @@ class ProfileHeader extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account, intl } = this.props
|
||||
const {
|
||||
account,
|
||||
children,
|
||||
intl,
|
||||
} = this.props
|
||||
const { stickied } = this.state
|
||||
|
||||
const tabs = !account ? null : [
|
||||
@@ -108,7 +115,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
||||
const headerSrc = !!account ? account.get('header') : ''
|
||||
const headerMissing = headerSrc.indexOf(PLACEHOLDER_MISSING_HEADER_SRC) > -1 || !headerSrc
|
||||
const avatarSize = headerMissing ? 75 : 150
|
||||
const top = headerMissing ? -30 : -380
|
||||
const top = headerMissing ? -46 : -380
|
||||
|
||||
const avatarContainerClasses = CX({
|
||||
default: 1,
|
||||
@@ -130,55 +137,51 @@ class ProfileHeader extends ImmutablePureComponent {
|
||||
displayNone: stickied,
|
||||
})
|
||||
|
||||
const mobileAvatarContainerClasses = CX({
|
||||
default: 1,
|
||||
circle: 1,
|
||||
boxShadowProfileAvatar: 1,
|
||||
mtNeg50PX: !headerMissing,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.z1, _s.width100PC].join(' ')}>
|
||||
<Sticky top={top} enabled onStateChange={this.onStickyStateChange}>
|
||||
<Responsive max={BREAKPOINT_EXTRA_SMALL}>
|
||||
<div className={[_s.default, _s.z1, _s.width100PC, _s.alignItemsCenter, _s.boxShadowBlock, _s.bgPrimary].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.width1015PX].join(' ')}>
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
{
|
||||
!headerMissing &&
|
||||
<div className={[_s.default, _s.height350PX, _s.width100PC, _s.bottomRightRadiusSmall, _s.bottomLeftRadiusSmall, _s.overflowHidden].join(' ')}>
|
||||
<div className={[_s.default, _s.height200PX, _s.px10, _s.width100PC, _s.mt10, _s.overflowHidden].join(' ')}>
|
||||
<Image
|
||||
alt={intl.formatMessage(messages.headerPhoto)}
|
||||
className={_s.height350PX}
|
||||
className={[_s.topRightRadiusSmall, _s.topLeftRadiusSmall, _s.height100PC].join(' ')}
|
||||
src={headerSrc}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
headerMissing &&
|
||||
<div className={[_s.default, _s.py10, _s.width100PC].join(' ')} />
|
||||
<div className={[_s.default, _s.height20PX, _s.width100PC].join(' ')} />
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.pr15, _s.pl25, _s.mb5].join(' ')}>
|
||||
<div className={avatarContainerClasses}>
|
||||
<Avatar size={avatarSize} account={account} noHover />
|
||||
<div className={[_s.default, _s.alignItemsCenter, _s.px15, _s.mb5].join(' ')}>
|
||||
<div className={mobileAvatarContainerClasses}>
|
||||
<Avatar size={100} account={account} noHover />
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.px15, _s.flexNormal, _s.py10].join(' ')}>
|
||||
<div className={[_s.default, _s.flexRow, _s.flexNormal, _s.py10].join(' ')}>
|
||||
<DisplayName account={account} isMultiline noRelationship isLarge noHover />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.bgPrimary, _s.height53PX].join(' ')}>
|
||||
<div className={tabBarContainerClasses}>
|
||||
<TabBar tabs={tabs} isLarge />
|
||||
</div>
|
||||
|
||||
<div className={stickyBarContainerClasses}>
|
||||
<Avatar size={36} account={account} noHover />
|
||||
<div className={[_s.default, _s.ml10].join(' ')}>
|
||||
<DisplayName account={account} noUsername noRelationship noHover isLarge />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.bgPrimary, _s.alignItemsCenter].join(' ')}>
|
||||
{
|
||||
account && account.get('id') === me &&
|
||||
<div className={[_s.default, _s.flexRow, _s.mlAuto, _s.py5].join(' ')}>
|
||||
<div className={[_s.default,_s.py5].join(' ')}>
|
||||
<Button
|
||||
isOutline
|
||||
backgroundColor='none'
|
||||
@@ -195,18 +198,7 @@ class ProfileHeader extends ImmutablePureComponent {
|
||||
|
||||
{
|
||||
account && account.get('id') !== me &&
|
||||
<div className={[_s.default, _s.flexRow, _s.mlAuto, _s.py5].join(' ')}>
|
||||
<Button
|
||||
isOutline
|
||||
icon='ellipsis'
|
||||
iconSize='18px'
|
||||
iconClassName={_s.inheritFill}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||
onClick={this.handleOpenMore}
|
||||
buttonRef={this.setOpenMoreNodeRef}
|
||||
/>
|
||||
<div className={[_s.default, _s.flexRow, _s.py5].join(' ')}>
|
||||
|
||||
<form action='https://chat.gab.com/private-message' method='POST'>
|
||||
<Button
|
||||
@@ -221,16 +213,148 @@ class ProfileHeader extends ImmutablePureComponent {
|
||||
/>
|
||||
<input type='hidden' value={account.get('username')} name='username' />
|
||||
</form>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.pb3, _s.mr10].join(' ')}>
|
||||
<AccountActionButton account={account} />
|
||||
</div>
|
||||
|
||||
<AccountActionButton account={account} />
|
||||
<div>
|
||||
<Button
|
||||
isOutline
|
||||
icon='ellipsis'
|
||||
iconSize='18px'
|
||||
iconClassName={_s.inheritFill}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.px10].join(' ')}
|
||||
onClick={this.handleOpenMore}
|
||||
buttonRef={this.setOpenMoreNodeRef}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.width100PC, _s.px15, _s.mt15, _s.mb10, _s.pt15, _s.pb10].join(' ')}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.mt10].join(' ')}>
|
||||
<TabBar tabs={tabs} isLarge />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Sticky>
|
||||
|
||||
</Responsive>
|
||||
|
||||
{ /** desktop */ }
|
||||
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
|
||||
<Sticky top={top} enabled onStateChange={this.onStickyStateChange}>
|
||||
<div className={[_s.default, _s.z1, _s.width100PC, _s.alignItemsCenter, _s.boxShadowBlock, _s.bgPrimary].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.width1015PX].join(' ')}>
|
||||
{
|
||||
!headerMissing &&
|
||||
<div className={[_s.default, _s.height350PX, _s.width100PC, _s.bottomRightRadiusSmall, _s.bottomLeftRadiusSmall, _s.overflowHidden].join(' ')}>
|
||||
<Image
|
||||
alt={intl.formatMessage(messages.headerPhoto)}
|
||||
className={_s.height100PC}
|
||||
src={headerSrc}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
headerMissing &&
|
||||
<div className={[_s.default, _s.height20PX, _s.width100PC].join(' ')} />
|
||||
}
|
||||
|
||||
<div className={[_s.default, _s.width100PC].join(' ')}>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.pr15, _s.pl25, _s.mb5].join(' ')}>
|
||||
<div className={avatarContainerClasses}>
|
||||
<Avatar size={avatarSize} account={account} noHover />
|
||||
</div>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.px15, _s.flexNormal, _s.py10].join(' ')}>
|
||||
<DisplayName account={account} isMultiline noRelationship isLarge noHover />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.bgPrimary, _s.height53PX].join(' ')}>
|
||||
<div className={tabBarContainerClasses}>
|
||||
<TabBar tabs={tabs} isLarge />
|
||||
</div>
|
||||
|
||||
<div className={stickyBarContainerClasses}>
|
||||
<Avatar size={36} account={account} noHover />
|
||||
<div className={[_s.default, _s.ml10].join(' ')}>
|
||||
<DisplayName account={account} noUsername noRelationship noHover isLarge />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
account && account.get('id') === me &&
|
||||
<div className={[_s.default, _s.flexRow, _s.mlAuto, _s.py5].join(' ')}>
|
||||
<Button
|
||||
isOutline
|
||||
backgroundColor='none'
|
||||
color='brand'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter].join(' ')}
|
||||
onClick={this.handleOnEditProfile}
|
||||
>
|
||||
<Text color='inherit' weight='bold' size='medium' className={_s.px15}>
|
||||
{intl.formatMessage(messages.editProfile)}
|
||||
</Text>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
account && account.get('id') !== me &&
|
||||
<div className={[_s.default, _s.flexRow, _s.mlAuto, _s.py5].join(' ')}>
|
||||
<div>
|
||||
<Button
|
||||
isOutline
|
||||
icon='ellipsis'
|
||||
iconSize='18px'
|
||||
iconClassName={_s.inheritFill}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||
onClick={this.handleOpenMore}
|
||||
buttonRef={this.setOpenMoreNodeRef}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<form action='https://chat.gab.com/private-message' method='POST'>
|
||||
<Button
|
||||
isOutline
|
||||
type='submit'
|
||||
icon='chat'
|
||||
iconSize='18px'
|
||||
iconClassName={_s.inheritFill}
|
||||
color='brand'
|
||||
backgroundColor='none'
|
||||
className={[_s.justifyContentCenter, _s.alignItemsCenter, _s.mr10, _s.px10].join(' ')}
|
||||
/>
|
||||
<input type='hidden' value={account.get('username')} name='username' />
|
||||
</form>
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.pb3].join(' ')}>
|
||||
<AccountActionButton account={account} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Sticky>
|
||||
</Responsive>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import BackButton from './back_button'
|
||||
import Heading from './heading'
|
||||
|
||||
export default class ProfileNavigationBar extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
showBackBtn: PropTypes.bool,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title } = this.props
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.z4, _s.height53PX, _s.width100PC].join(' ')}>
|
||||
<div className={[_s.default, _s.height53PX, _s.bgNavigation, _s.alignItemsCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')} >
|
||||
|
||||
<div className={[_s.default, _s.flexRow, _s.width100PC].join(' ')}>
|
||||
|
||||
<BackButton
|
||||
classNames={[_s.height53PX, _s.bgTransparent, _s.ml10, _s.mr10, _s.cursorPointer, _s.outlineNone, _s.default, _s.justifyContentCenter].join(' ')}
|
||||
iconSize='32px'
|
||||
iconClassName={[_s.mr5, _s.fillNavigation].join(' ')}
|
||||
/>
|
||||
|
||||
<div className={[_s.default, _s.height53PX, _s.justifyContentCenter, _s.mrAuto].join(' ')}>
|
||||
<Heading size='h1'>
|
||||
<span className={[_s.textOverflowEllipsis, _s.colorNavigation].join(' ')}>
|
||||
{title}
|
||||
</span>
|
||||
</Heading>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import queryString from 'query-string'
|
||||
import { me } from '../initial_state'
|
||||
import { CX } from '../constants'
|
||||
import {
|
||||
changeSearch,
|
||||
@@ -128,7 +129,7 @@ class Search extends PureComponent {
|
||||
})
|
||||
|
||||
const prependIconColor = highlighted ? 'brand' : 'white'
|
||||
|
||||
const placeholder = !me ? 'Search Gab' : 'Search for people, groups or news'
|
||||
const id = 'nav-search'
|
||||
|
||||
return (
|
||||
@@ -140,7 +141,7 @@ class Search extends PureComponent {
|
||||
id={id}
|
||||
className={inputClasses}
|
||||
type='text'
|
||||
placeholder='Search for people, groups or news'
|
||||
placeholder={placeholder}
|
||||
ref={this.setTextbox}
|
||||
value={value}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
|
||||
@@ -12,6 +12,7 @@ import Responsive from '../features/ui/util/responsive_component'
|
||||
import SidebarSectionTitle from './sidebar_section_title'
|
||||
import SidebarSectionItem from './sidebar_section_item'
|
||||
import Heading from './heading'
|
||||
import BackButton from './back_button'
|
||||
import Pills from './pills'
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -227,16 +228,7 @@ class Sidebar extends ImmutablePureComponent {
|
||||
<div className={[_s.default, _s.flexRow, _s.px5, _s.pt10].join(' ')}>
|
||||
{
|
||||
showBackBtn &&
|
||||
<Button
|
||||
noClasses
|
||||
color='primary'
|
||||
backgroundColor='none'
|
||||
className={[_s.alignItemsCenter, _s.bgTransparent, _s.mr5, _s.cursorPointer, _s.outlineNone, _s.default, _s.justifyContentCenter].join(' ')}
|
||||
icon='arrow-left'
|
||||
iconSize='24px'
|
||||
iconClassName={[_s.mr5, _s.fillPrimary].join(' ')}
|
||||
onClick={this.handleBackClick}
|
||||
/>
|
||||
<BackButton />
|
||||
}
|
||||
<Heading size='h1'>
|
||||
{title}
|
||||
|
||||
@@ -535,9 +535,12 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
{
|
||||
!isChild && !compactMode && !!me &&
|
||||
<div className={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px15, _s.mb10].join(' ')}>
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px15, _s.mb10].join(' ')}
|
||||
classNamesXS={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px10, _s.mb10].join(' ')}
|
||||
>
|
||||
<ComposeFormContainer replyToId={status.get('id')} shouldCondense />
|
||||
</div>
|
||||
</ResponsiveClassesComponent>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component';
|
||||
import TabBarItem from './tab_bar_item'
|
||||
|
||||
/**
|
||||
@@ -16,7 +17,10 @@ export default class TabBar extends PureComponent {
|
||||
const { tabs, isLarge } = this.props
|
||||
|
||||
return (
|
||||
<div className={[_s.default, _s.height53PX, _s.px5, _s.flexRow].join(' ')}>
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.default, _s.height53PX, _s.px5, _s.flexRow].join(' ')}
|
||||
classNamesXS={[_s.default, _s.height40PX, _s.px5, _s.flexRow].join(' ')}
|
||||
>
|
||||
{
|
||||
// Check for if tabs exist or not.
|
||||
// We don't `return null` because it maintains 53px height if no tabs.
|
||||
@@ -32,7 +36,7 @@ export default class TabBar extends PureComponent {
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</ResponsiveClassesComponent>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class TabBarItem extends PureComponent {
|
||||
|
||||
const containerClasses = CX({
|
||||
default: 1,
|
||||
height53PX: 1,
|
||||
height100PC: 1,
|
||||
noUnderline: 1,
|
||||
text: 1,
|
||||
displayFlex: 1,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { CX } from '../constants'
|
||||
import Text from './text'
|
||||
|
||||
/**
|
||||
@@ -17,6 +18,7 @@ export default class UserStat extends PureComponent {
|
||||
PropTypes.number,
|
||||
PropTypes.object,
|
||||
]).isRequired,
|
||||
isCentered: PropTypes.bool.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
@@ -32,21 +34,36 @@ export default class UserStat extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { to, title, value } = this.props
|
||||
const {
|
||||
to,
|
||||
title,
|
||||
value,
|
||||
isCentered,
|
||||
} = this.props
|
||||
const { hovering } = this.state
|
||||
|
||||
const align = isCentered ? 'center' : 'left'
|
||||
const containerClasses = CX({
|
||||
default: 1,
|
||||
cursorPointer: 1,
|
||||
noUnderline: 1,
|
||||
flexNormal: isCentered,
|
||||
flexGrow1: !isCentered,
|
||||
pr15: !isCentered,
|
||||
})
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
to={to}
|
||||
title={`${value} ${title}`}
|
||||
className={[_s.default, _s.flexGrow1, _s.cursorPointer, _s.noUnderline, _s.pr15].join(' ')}
|
||||
className={containerClasses}
|
||||
onMouseEnter={this.handleOnMouseEnter}
|
||||
onMouseLeave={this.handleOnMouseLeave}
|
||||
>
|
||||
<Text size='large' weight='bold' color='brand'>
|
||||
<Text size='large' weight='bold' color='brand' align={align}>
|
||||
{value}
|
||||
</Text>
|
||||
<Text size='small' weight='medium' color='secondary' hasUnderline={hovering}>
|
||||
<Text size='small' weight='medium' color='secondary' hasUnderline={hovering} align={align}>
|
||||
{title}
|
||||
</Text>
|
||||
</NavLink>
|
||||
|
||||
Reference in New Issue
Block a user