This commit is contained in:
mgabdev 2020-05-06 00:33:54 -04:00
parent 01bb440385
commit e1e26afe11
23 changed files with 501 additions and 292 deletions

View File

@ -40,7 +40,6 @@ export const fetchGifResults = (expand) => {
const pos = 0 //expand ? getState().getIn(['tenor', 'results'], []).length const pos = 0 //expand ? getState().getIn(['tenor', 'results'], []).length
api(getState).get('/api/v1/gifs/search', { search, pos }).then((response) => { api(getState).get('/api/v1/gifs/search', { search, pos }).then((response) => {
console.log("response.data:", response.data)
dispatch(fetchGifResultsSuccess(response.data)) dispatch(fetchGifResultsSuccess(response.data))
}).catch(function (error) { }).catch(function (error) {
dispatch(fetchGifResultsFail(error)) dispatch(fetchGifResultsFail(error))

View File

@ -175,7 +175,7 @@ class Comment extends ImmutablePureComponent {
isComment isComment
collapsable collapsable
/> />
<div className={[_s.default].join(' ')}> <div className={[_s.default, _s.mt5].join(' ')}>
<StatusMedia <StatusMedia
isComment isComment
status={status} status={status}

View File

@ -31,7 +31,7 @@ class FloatingActionButton extends PureComponent {
return ( return (
<Button <Button
onClick={onOpenCompose} onClick={onOpenCompose}
className={[_s.posFixed, _s.z4, _s.py15, _s.mb15, _s.mr15, _s.bottom0, _s.right0].join(' ')} className={[_s.posFixed, _s.z4, _s.py15, _s.mb15, _s.mr15, _s.bottom50PX, _s.right0].join(' ')}
title={message} title={message}
aria-label={message} aria-label={message}
icon='pencil' icon='pencil'

View File

@ -1,59 +0,0 @@
import { NavLink, withRouter } from 'react-router-dom';
import { FormattedMessage, injectIntl } from 'react-intl';
import NotificationCounter from '../notification_counter';
// : todo :
const links = [
<NavLink key='pr1' className='footer-bar__link' to='/home' data-preview-title-id='column.home'>
<i className='tabs-bar__link__icon home' />
<FormattedMessage id='tabs_bar.home' defaultMessage='Home' />
</NavLink>,
<NavLink key='pr2' className='footer-bar__link' to='/notifications' data-preview-title-id='column.notifications'>
<i className='tabs-bar__link__icon notifications'/>
<NotificationCounter />
<FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' />
</NavLink>,
<a key='pl5' className='footer-bar__link footer-bar__link--chat' href='https://chat.gab.com' data-preview-title-id='tabs_bar.chat'>
<Icon id='comments' className='tabs-bar__link__icon chat' />
<FormattedMessage id='tabs_bar.chat' defaultMessage='Chat' />
</a>,
<a key='pl4' className='footer-bar__link footer-bar__link--trends' href='https://trends.gab.com' data-preview-title-id='tabs_bar.trends'>
<i className='tabs-bar__link__icon trends' />
<FormattedMessage id='tabs_bar.trends' defaultMessage='Trends' />
</a>,
<NavLink key='pr3' className='footer-bar__link' to='/groups' data-preview-title-id='column.groups'>
<i className='tabs-bar__link__icon groups' />
<FormattedMessage id='tabs_bar.groups' defaultMessage='Groups' />
</NavLink>,
]
export default
@injectIntl
@withRouter
class FooterBar extends PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
}
render() {
const { intl: { formatMessage } } = this.props;
return (
<div className='footer-bar'>
<div className='footer-bar__container'>
{
links.map((link) =>
React.cloneElement(link, {
key: link.props.to,
'aria-label': formatMessage({
id: link.props['data-preview-title-id']
})
}))
}
</div>
</div>
);
}
}

View File

@ -0,0 +1,88 @@
import { NavLink, withRouter } from 'react-router-dom';
import { FormattedMessage, injectIntl } from 'react-intl';
import Button from './button'
import Icon from './icon'
const links = [
<NavLink key='pr1' className='footer-bar__link' to='/home' data-preview-title-id='column.home'>
<i className='tabs-bar__link__icon home' />
<FormattedMessage id='tabs_bar.home' defaultMessage='Home' />
</NavLink>,
<NavLink key='pr2' className='footer-bar__link' to='/notifications' data-preview-title-id='column.notifications'>
<i className='tabs-bar__link__icon notifications' />
<FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' />
</NavLink>,
<a key='pl5' className='footer-bar__link footer-bar__link--chat' href='https://chat.gab.com' data-preview-title-id='tabs_bar.chat'>
<FormattedMessage id='tabs_bar.chat' defaultMessage='Chat' />
</a>,
<a key='pl4' className='footer-bar__link footer-bar__link--trends' href='https://trends.gab.com' data-preview-title-id='tabs_bar.trends'>
<i className='tabs-bar__link__icon trends' />
<FormattedMessage id='tabs_bar.trends' defaultMessage='Trends' />
</a>,
<NavLink key='pr3' className='footer-bar__link' to='/groups' data-preview-title-id='column.groups'>
<i className='tabs-bar__link__icon groups' />
<FormattedMessage id='tabs_bar.groups' defaultMessage='Groups' />
</NavLink>,
]
export default
@injectIntl
@withRouter
class FooterBar extends PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
}
handleSettings = () => {
//
}
render() {
const { intl } = this.props
return (
<div className={[_s.default, _s.z4, _s.height53PX, _s.width100PC].join(' ')}>
<div className={[_s.default, _s.posFixed, _s.left0, _s.right0, _s.bottom0, _s.height53PX, _s.width100PC, _s.bgPrimary, _s.borderTop1PX, _s.borderColorSecondary].join(' ')}>
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.justifyContentSpaceAround].join(' ')}>
<Button
backgroundColor='none'
color='secondary'
to='/home'
icon='home'
iconSize='20px'
/>
<Button
backgroundColor='none'
color='secondary'
to='/search'
icon='search'
iconSize='20px'
/>
<Button
backgroundColor='none'
color='secondary'
to='/notifications'
icon='notifications'
iconSize='20px'
/>
<Button
backgroundColor='none'
color='secondary'
to='/groups'
icon='group'
iconSize='20px'
/>
<Button
backgroundColor='none'
color='secondary'
onClick={this.handleSettings}
icon='hamburger'
iconSize='20px'
/>
</div>
</div>
</div>
)
}
}

View File

@ -46,7 +46,7 @@ class IntersectionObserverArticle extends React.Component {
state = { state = {
isIntersecting: false, isIntersecting: false,
isHidden: true, isHidden: false,
} }
componentDidMount() { componentDidMount() {
@ -142,7 +142,7 @@ class IntersectionObserverArticle extends React.Component {
data-id={id} data-id={id}
tabIndex='0' tabIndex='0'
> >
{React.cloneElement(children, { isHidden: true })} {React.cloneElement(children, { isHidden: true, cachedHeight })}
</article> </article>
) )
} }
@ -155,7 +155,7 @@ class IntersectionObserverArticle extends React.Component {
data-id={id} data-id={id}
tabIndex='0' tabIndex='0'
> >
{React.cloneElement(children, { isHidden: false, isIntersecting })} {React.cloneElement(children, { isHidden: false, isIntersecting, cachedHeight })}
</article> </article>
) )
} }

View File

@ -253,6 +253,7 @@ class MediaGallery extends PureComponent {
visible: PropTypes.bool, visible: PropTypes.bool,
onToggleVisibility: PropTypes.func, onToggleVisibility: PropTypes.func,
reduced: PropTypes.bool, reduced: PropTypes.bool,
isComment: PropTypes.bool,
}; };
static defaultProps = { static defaultProps = {

View File

@ -7,6 +7,7 @@ import Responsive from '../features/ui/util/responsive_component'
import { CX } from '../constants' import { CX } from '../constants'
import Avatar from './avatar' import Avatar from './avatar'
import Button from './button' import Button from './button'
import Heading from './heading'
import Icon from './icon' import Icon from './icon'
import Search from './search' import Search from './search'
import Text from './text' import Text from './text'
@ -48,11 +49,31 @@ class NavigationBar extends ImmutablePureComponent {
<div className={[_s.default, _s.flexRow].join(' ')}> <div className={[_s.default, _s.flexRow].join(' ')}>
<h1 className={[_s.default, _s.mr15].join(' ')}> <Responsive max={BREAKPOINT_EXTRA_SMALL}>
<Button to='/' isText title='Gab' 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} /> !!account &&
</Button> <button
</h1> title={account.get('display_name')}
onClick={this.handleProfileClick}
className={[_s.height53PX, _s.bgTransparent, _s.outlineNone, _s.cursorPointer, _s.default, _s.justifyContentCenter, _s.ml15].join(' ')}
>
<Avatar account={account} size={32} noHover />
</button>
}
<div className={[_s.default, _s.height53PX, _s.justifyContentCenter, _s.mlAuto, _s.mrAuto].join(' ')}>
<Heading size='h1'>
{title}
</Heading>
</div>
</Responsive>
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
<h1 className={[_s.default, _s.mr15].join(' ')}>
<Button to='/' isText title='Gab' 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} />
</Button>
</h1>
</Responsive>
<Responsive min={BREAKPOINT_EXTRA_SMALL}> <Responsive min={BREAKPOINT_EXTRA_SMALL}>
<div className={[_s.default, _s.width340PX].join(' ')}> <div className={[_s.default, _s.width340PX].join(' ')}>
@ -64,25 +85,34 @@ class NavigationBar extends ImmutablePureComponent {
<div className={[_s.default, _s.mlAuto].join(' ')}> <div className={[_s.default, _s.mlAuto].join(' ')}>
<div className={[_s.default, _s.height53PX, _s.pl15, _s.flexRow, _s.alignItemsCenter, _s.justifyContentSpaceBetween].join(' ')}> <div className={[_s.default, _s.height53PX, _s.pl15, _s.flexRow, _s.alignItemsCenter, _s.justifyContentSpaceBetween].join(' ')}>
<NavigationBarButton title='Home' icon='home' to='/home' />
<NavigationBarButtonDivider /> <Responsive min={BREAKPOINT_EXTRA_SMALL}>
<div>
{ /** actions */}
</div>
</Responsive>
<NavigationBarButton attrTitle='Notifications' icon='notifications' to='/notifications' /> <Responsive min={BREAKPOINT_EXTRA_SMALL}>
<NavigationBarButton attrTitle='Settings' icon='cog' href='/settings/preferences' /> <NavigationBarButton title='Home' icon='home' to='/home' />
<NavigationBarButtonDivider /> <NavigationBarButtonDivider />
{ <NavigationBarButton attrTitle='Notifications' icon='notifications' to='/notifications' />
!!account && <NavigationBarButton attrTitle='Settings' icon='cog' href='/settings/preferences' />
<button
title={account.get('display_name')} <NavigationBarButtonDivider />
onClick={this.handleProfileClick}
className={[_s.height53PX, _s.bgTransparent, _s.outlineNone, _s.cursorPointer, _s.default, _s.justifyContentCenter, _s.ml15].join(' ')} {
> !!account &&
<Avatar account={account} size={32} noHover /> <button
</button> title={account.get('display_name')}
} onClick={this.handleProfileClick}
className={[_s.height53PX, _s.bgTransparent, _s.outlineNone, _s.cursorPointer, _s.default, _s.justifyContentCenter, _s.ml15].join(' ')}
>
<Avatar account={account} size={32} noHover />
</button>
}
</Responsive>
</div> </div>
</div> </div>

View File

@ -1,9 +1,11 @@
import classNames from 'classnames/bind' import {
CX,
BREAKPOINT_SMALL
} from '../constants'
import Button from './button' import Button from './button'
import Icon from './icon' import Icon from './icon'
import Image from './image' import Image from './image'
import Responsive from '../features/ui/util/responsive_component'
const cx = classNames.bind(_s)
export default class SidebarSectionItem extends PureComponent { export default class SidebarSectionItem extends PureComponent {
@ -57,7 +59,7 @@ export default class SidebarSectionItem extends PureComponent {
const shouldShowActive = hovering || active || currentPathname === to || currentPathname === href const shouldShowActive = hovering || active || currentPathname === to || currentPathname === href
const isNotifications = to === '/notifications' const isNotifications = to === '/notifications'
const containerClasses = cx({ const containerClasses = CX({
default: 1, default: 1,
maxWidth100PC: 1, maxWidth100PC: 1,
width100PC: 1, width100PC: 1,
@ -74,7 +76,7 @@ export default class SidebarSectionItem extends PureComponent {
bgPrimary: shouldShowActive, bgPrimary: shouldShowActive,
}) })
const textClasses = cx({ const textClasses = CX({
default: 1, default: 1,
fontWeightNormal: 1, fontWeightNormal: 1,
fs15PX: 1, fs15PX: 1,
@ -83,11 +85,11 @@ export default class SidebarSectionItem extends PureComponent {
colorPrimary: 1, colorPrimary: 1,
}) })
const iconClasses = cx({ const iconClasses = CX({
fillPrimary: 1, fillPrimary: 1,
}) })
const countClasses = cx({ const countClasses = CX({
default: 1, default: 1,
text: 1, text: 1,
mlAuto: 1, mlAuto: 1,
@ -130,9 +132,11 @@ export default class SidebarSectionItem extends PureComponent {
/> />
} }
<div className={[_s.default, _s.flexNormal, _s.px10, _s.textOverflowEllipsis, _s.overflowWrapBreakWord, _s.flexRow, _s.width100PC].join(' ')}> <Responsive min={BREAKPOINT_SMALL}>
<span className={textClasses}>{title}</span> <div className={[_s.default, _s.flexNormal, _s.px10, _s.textOverflowEllipsis, _s.overflowWrapBreakWord, _s.flexRow, _s.width100PC].join(' ')}>
</div> <span className={textClasses}>{title}</span>
</div>
</Responsive>
{ {
count > 0 && count > 0 &&

View File

@ -4,7 +4,10 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
import { HotKeys } from 'react-hotkeys' import { HotKeys } from 'react-hotkeys'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { me, displayMedia, compactMode } from '../initial_state' import { me, displayMedia, compactMode } from '../initial_state'
import scheduleIdleTask from '../utils/schedule_idle_task'
import ComposeFormContainer from '../features/compose/containers/compose_form_container' import ComposeFormContainer from '../features/compose/containers/compose_form_container'
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
import ColumnIndicator from './column_indicator'
import StatusContent from './status_content' import StatusContent from './status_content'
import StatusPrepend from './status_prepend' import StatusPrepend from './status_prepend'
import StatusActionBar from './status_action_bar' import StatusActionBar from './status_action_bar'
@ -133,12 +136,14 @@ class Status extends ImmutablePureComponent {
if (nextProps.isChild) return null if (nextProps.isChild) return null
if (!nextProps.isHidden && (nextProps.isIntersecting || !nextProps.commentsLimited) && !prevState.loadedComments) { if (!nextProps.isHidden && (nextProps.isIntersecting || !nextProps.commentsLimited) && !prevState.loadedComments) {
console.log("111111111111111111111111111111111111", nextProps.isHidden, nextProps.isIntersecting)
return { return {
loadedComments: true loadedComments: true
} }
} }
if (nextProps.status && nextProps.status.get('id') !== prevState.statusId) { if (nextProps.status && nextProps.status.get('id') !== prevState.statusId) {
console.log("2222222222222222222222222222222222222")
return { return {
loadedComments: false, //reset loadedComments: false, //reset
showMedia: defaultMediaVisibility(nextProps.status), showMedia: defaultMediaVisibility(nextProps.status),
@ -154,12 +159,14 @@ class Status extends ImmutablePureComponent {
// timeline lazy loading comments // timeline lazy loading comments
if (!prevState.loadedComments && this.state.loadedComments && this.props.status && !this.props.isChild) { if (!prevState.loadedComments && this.state.loadedComments && this.props.status && !this.props.isChild) {
const commentCount = this.props.status.get('replies_count') const commentCount = this.props.status.get('replies_count')
if (commentCount > 0 && !this.props.isComment) { if (this.props.isComment) {
this.props.onFetchComments(this.props.status.get('id'))
// this._measureHeight(prevState.height !== this.state.height)
} else {
console.log("before fetch:", this.props.status)
this.props.onFetchContext(this.props.status.get('id')) this.props.onFetchContext(this.props.status.get('id'))
this._measureHeight(prevState.height !== this.state.height)
} else {
if (commentCount > 0) {
this._measureHeight(prevState.height !== this.state.height)
this.props.onFetchComments(this.props.status.get('id'))
}
} }
} }
@ -170,6 +177,7 @@ class Status extends ImmutablePureComponent {
if (snapshot !== null && this.props.updateScrollBottom) { if (snapshot !== null && this.props.updateScrollBottom) {
if (this.node && this.node.offsetTop < snapshot.top) { if (this.node && this.node.offsetTop < snapshot.top) {
console.log("updateScrollBottom")
this.props.updateScrollBottom(snapshot.height - snapshot.top) this.props.updateScrollBottom(snapshot.height - snapshot.top)
} }
} }
@ -332,7 +340,7 @@ class Status extends ImmutablePureComponent {
return status return status
} }
_measureHeight (heightJustChanged) { _measureHeight(heightJustChanged) {
try { try {
scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 })) scheduleIdleTask(() => this.node && this.setState({ height: Math.ceil(this.node.scrollHeight) + 1 }))
@ -340,7 +348,7 @@ class Status extends ImmutablePureComponent {
this.props.onHeightChange() this.props.onHeightChange()
} }
} catch (error) { } catch (error) {
//
} }
} }
@ -360,12 +368,18 @@ class Status extends ImmutablePureComponent {
commentsLimited, commentsLimited,
ancestorStatus, ancestorStatus,
isComment, isComment,
contextType,
} = this.props } = this.props
// const { height } = this.state
let { status } = this.props let { status } = this.props
if (!status) return null if (!status) return null
if (isComment && !ancestorStatus && !isChild) {
return <ColumnIndicator type='loading' />
}
let reblogContent, rebloggedByText = null let reblogContent, rebloggedByText = null
if (ancestorStatus) { if (ancestorStatus) {
@ -394,35 +408,27 @@ class Status extends ImmutablePureComponent {
toggleSensitive: this.handleHotkeyToggleSensitive, toggleSensitive: this.handleHotkeyToggleSensitive,
} }
if (isHidden) { const parentClasses = cx({
return ( pb15: !isChild && !compactMode,
<HotKeys handlers={handlers}> })
<div ref={this.handleRef} className={classNames({ focusable: !this.props.muted })} tabIndex='0'>
{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}
{status.get('content')}
</div>
</HotKeys>
)
}
if (status.get('filtered') || status.getIn(['reblog', 'filtered'])) {
return null
}
const containerClasses = cx({ const containerClasses = cx({
default: 1,
pb15: isFeatured,
radiusSmall: !isChild && !compactMode, radiusSmall: !isChild && !compactMode,
bgPrimary: !isChild, bgPrimary: !isChild,
boxShadowBlock: !isChild && !compactMode, boxShadowBlock: !isChild && !compactMode,
outlineNone: 1,
mb15: !isChild && !compactMode,
borderRight1PX: !isChild && compactMode, borderRight1PX: !isChild && compactMode,
borderLeft1PX: !isChild && compactMode, borderLeft1PX: !isChild && compactMode,
borderBottom1PX: !isChild && compactMode, borderBottom1PX: !isChild && compactMode,
borderColorSecondary: !isChild && compactMode, borderColorSecondary: !isChild && compactMode,
}) })
const containerClassesXS = cx({
bgPrimary: !isChild,
boxShadowBlock: !isChild && !compactMode,
borderBottom1PX: !isChild && compactMode,
borderColorSecondary: !isChild && compactMode,
})
const innerContainerClasses = cx({ const innerContainerClasses = cx({
default: 1, default: 1,
overflowHidden: 1, overflowHidden: 1,
@ -435,95 +441,117 @@ class Status extends ImmutablePureComponent {
bgSubtle_onHover: isChild, bgSubtle_onHover: isChild,
}) })
if (status.get('filtered') || status.getIn(['reblog', 'filtered'])) {
return null
}
if (isHidden) {
return (
<HotKeys handlers={handlers}>
<div ref={this.handleRef} className={parentClasses} tabIndex='0'>
{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}
{status.get('content')}
</div>
</HotKeys>
)
}
return ( return (
<HotKeys handlers={handlers}> <HotKeys handlers={handlers}>
<div <div className={parentClasses}>
className={containerClasses} <ResponsiveClassesComponent
tabIndex={this.props.isMuted ? null : 0} classNames={containerClasses}
data-featured={isFeatured ? 'true' : null} classNamesXS={containerClassesXS}
aria-label={textForScreenReader(intl, status, rebloggedByText)} >
ref={this.handleRef} <div
onClick={isChild ? this.handleClick : undefined} className={[_s.default, _s.outlineNone].join(' ')}
> tabIndex={this.props.isMuted ? null : 0}
<div className={innerContainerClasses}> data-featured={isFeatured ? 'true' : null}
aria-label={textForScreenReader(intl, status, rebloggedByText)}
ref={this.handleRef}
onClick={isChild ? this.handleClick : undefined}
>
<div className={innerContainerClasses}>
<div data-id={status.get('id')}> <div data-id={status.get('id')}>
<StatusPrepend <StatusPrepend
status={this.props.status} status={this.props.status}
isPromoted={isPromoted} isPromoted={isPromoted}
isFeatured={isFeatured} isFeatured={isFeatured}
isComment={isComment} isComment={isComment && !isChild}
/> />
<StatusHeader status={status} reduced={isChild} /> <StatusHeader status={status} reduced={isChild} />
<div className={_s.default}> <div className={_s.default}>
<StatusContent <StatusContent
status={status} status={status}
reblogContent={reblogContent} reblogContent={reblogContent}
onClick={this.handleClick} onClick={this.handleClick}
expanded={!status.get('hidden')} expanded={!status.get('hidden')}
onExpandedToggle={this.handleExpandedToggle} onExpandedToggle={this.handleExpandedToggle}
collapsable collapsable={contextType !== 'feature'}
/> />
</div>
<StatusMedia
isChild={isChild}
status={status}
onOpenMedia={this.props.onOpenMedia}
cacheWidth={this.props.cacheMediaWidth}
defaultWidth={this.props.cachedMediaWidth}
visible={this.state.showMedia}
onToggleVisibility={this.handleToggleMediaVisibility}
width={this.props.cachedMediaWidth}
onOpenVideo={this.handleOpenVideo}
/>
{
!!status.get('quote') && !isChild &&
<div className={[_s.default, _s.mt10, _s.px10].join(' ')}>
<Status status={status.get('quoted_status')} isChild intl={intl} />
</div>
}
{
!isChild &&
<StatusActionBar
status={status}
onFavorite={this.props.onFavorite}
onReply={this.props.onReply}
onRepost={this.props.onRepost}
onShare={this.props.onShare}
onOpenLikes={this.props.onOpenLikes}
onOpenReposts={this.props.onOpenReposts}
/>
}
{
!isChild && !compactMode && !!me &&
<div className={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px15, _s.mb10].join(' ')}>
<ComposeFormContainer replyToId={status.get('id')} shouldCondense />
</div>
}
{
descendantsIds && !compactMode && !isChild && descendantsIds.size > 0 &&
<div className={[_s.default, _s.mr10, _s.ml10, _s.mb10, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')} />
}
{
descendantsIds && !compactMode && !isChild && descendantsIds.size > 0 &&
<CommentList
ancestorAccountId={status.getIn(['account', 'id'])}
commentsLimited={commentsLimited}
descendants={descendantsIds}
onViewComments={this.handleClick}
/>
}
</div>
</div> </div>
<StatusMedia
isChild={isChild}
status={status}
onOpenMedia={this.props.onOpenMedia}
cacheWidth={this.props.cacheMediaWidth}
defaultWidth={this.props.cachedMediaWidth}
visible={this.state.showMedia}
onToggleVisibility={this.handleToggleMediaVisibility}
width={this.props.cachedMediaWidth}
onOpenVideo={this.handleOpenVideo}
/>
{
!!status.get('quote') && !isChild &&
<div className={[_s.default, _s.mt10, _s.px10].join(' ')}>
<Status status={status.get('quoted_status')} isChild intl={intl} />
</div>
}
{
!isChild &&
<StatusActionBar
status={status}
onFavorite={this.props.onFavorite}
onReply={this.props.onReply}
onRepost={this.props.onRepost}
onShare={this.props.onShare}
onOpenLikes={this.props.onOpenLikes}
onOpenReposts={this.props.onOpenReposts}
/>
}
{
!isChild && !compactMode && !!me &&
<div className={[_s.default, _s.borderTop1PX, _s.borderColorSecondary, _s.pt10, _s.px15, _s.mb10].join(' ')}>
<ComposeFormContainer replyToId={status.get('id')} shouldCondense />
</div>
}
{
descendantsIds && !compactMode && !isChild && descendantsIds.size > 0 &&
<div className={[_s.default, _s.mr10, _s.ml10, _s.mb10, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}/>
}
{
descendantsIds && !compactMode && !isChild && descendantsIds.size > 0 &&
<CommentList
ancestorAccountId={status.getIn(['account', 'id'])}
commentsLimited={commentsLimited}
descendants={descendantsIds}
onViewComments={this.handleClick}
/>
}
</div> </div>
</div> </ResponsiveClassesComponent>
</div> </div>
</HotKeys> </HotKeys>
) )

View File

@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import punycode from 'punycode' import punycode from 'punycode'
import { DEFAULT_REL } from '../constants' import { DEFAULT_REL } from '../constants'
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
import Icon from './icon' import Icon from './icon'
const IDNA_PREFIX = 'xn--' const IDNA_PREFIX = 'xn--'
@ -67,7 +68,7 @@ export default class Card extends ImmutablePureComponent {
embedded: false, embedded: false,
} }
componentWillReceiveProps (nextProps) { componentWillReceiveProps(nextProps) {
if (!Immutable.is(this.props.card, nextProps.card)) { if (!Immutable.is(this.props.card, nextProps.card)) {
this.setState({ embedded: false }) this.setState({ embedded: false })
} }
@ -111,12 +112,12 @@ export default class Card extends ImmutablePureComponent {
} }
} }
renderVideo () { renderVideo() {
const { card } = this.props const { card } = this.props
const content = { __html: addAutoPlay(card.get('html')) } const content = { __html: addAutoPlay(card.get('html')) }
const { width } = this.state const { width } = this.state
const ratio = card.get('width') / card.get('height') const ratio = card.get('width') / card.get('height')
const height = width / ratio const height = width / ratio
return ( return (
<div <div
@ -127,7 +128,7 @@ export default class Card extends ImmutablePureComponent {
) )
} }
render () { render() {
const { card } = this.props const { card } = this.props
const { width, embedded } = this.state const { width, embedded } = this.state
@ -175,7 +176,14 @@ export default class Card extends ImmutablePureComponent {
const thumbnail = interactive ? const thumbnail = interactive ?
<img alt={''} src={cardImg} className={[_s.default, _s.objectFitCover, _s.posAbs, _s.width100PC, _s.height100PC, _s.top0, _s.right0, _s.bottom0, _s.left0].join(' ')} /> <img alt={''} src={cardImg} className={[_s.default, _s.objectFitCover, _s.posAbs, _s.width100PC, _s.height100PC, _s.top0, _s.right0, _s.bottom0, _s.left0].join(' ')} />
: :
<img alt={''} src={cardImg} className={[_s.default, _s.objectFitCover, _s.width330PX, _s.height220PX].join(' ')} /> (
<ResponsiveClassesComponent
classNames={[_s.default, _s.height220PX, _s.width330PX].join(' ')}
classNamesSmall={[_s.default, _s.height260PX, _s.width100PC].join(' ')}
>
<img alt={''} src={cardImg} className={[_s.default, _s.objectFitCover, _s.width100PC, _s.height100PC].join(' ')} />
</ResponsiveClassesComponent>
)
if (interactive) { if (interactive) {
if (embedded) { if (embedded) {
@ -193,9 +201,9 @@ export default class Card extends ImmutablePureComponent {
<div className={[_s.default, _s.overflowHidden, _s.width100PC, _s.borderColorSecondary, _s.border1PX, _s.radiusSmall].join(' ')}> <div className={[_s.default, _s.overflowHidden, _s.width100PC, _s.borderColorSecondary, _s.border1PX, _s.radiusSmall].join(' ')}>
<div className={[_s.default, _s.width100PC].join(' ')}> <div className={[_s.default, _s.width100PC].join(' ')}>
<div className={[_s.default, _s.width100PC, _s.pt5625PC].join(' ')}> <div className={[_s.default, _s.width100PC, _s.pt5625PC].join(' ')}>
{ !!embed && embed} {!!embed && embed}
{ !embed && thumbnail} {!embed && thumbnail}
{ !embed && {!embed &&
<div className={[_s.default, _s.posAbs, _s.top0, _s.right0, _s.left0, _s.bottom0, _s.alignItemsCenter, _s.justifyContentCenter].join(' ')}> <div className={[_s.default, _s.posAbs, _s.top0, _s.right0, _s.left0, _s.bottom0, _s.alignItemsCenter, _s.justifyContentCenter].join(' ')}>
<button <button
className={[_s.default, _s.cursorPointer, _s.bgBlackOpaque, _s.radiusSmall, _s.py15, _s.px15].join(' ')} className={[_s.default, _s.cursorPointer, _s.bgBlackOpaque, _s.radiusSmall, _s.py15, _s.px15].join(' ')}
@ -229,12 +237,17 @@ export default class Card extends ImmutablePureComponent {
<div className={[_s.default, _s.width100PC, _s.px10].join(' ')}> <div className={[_s.default, _s.width100PC, _s.px10].join(' ')}>
<a <a
href={card.get('url')} href={card.get('url')}
className={[_s.default, _s.cursorPointer, _s.flexRow, _s.overflowHidden, _s.noUnderline, _s.width100PC, _s.bgSubtle_onHover, _s.borderColorSecondary, _s.border1PX, _s.radiusSmall].join(' ')}
rel={DEFAULT_REL} rel={DEFAULT_REL}
ref={this.setRef} ref={this.setRef}
className={[_s.default, _s.cursorPointer, _s.overflowHidden, _s.noUnderline, _s.width100PC, _s.bgSubtle_onHover, _s.borderColorSecondary, _s.border1PX, _s.radiusSmall].join(' ')}
> >
{embed} <ResponsiveClassesComponent
{description} classNames={[_s.default, _s.flexRow, _s.width100PC].join(' ')}
classNamesSmall={!cardImg ? undefined : [_s.default, _s.width100PC].join(' ')}
>
{embed}
{description}
</ResponsiveClassesComponent>
</a> </a>
</div> </div>
) )

View File

@ -169,7 +169,12 @@ class StatusContent extends ImmutablePureComponent {
} }
render() { render() {
const { status, intl, isComment } = this.props const {
collapsable,
intl,
isComment,
status,
} = this.props
const { collapsed } = this.state const { collapsed } = this.state
if (status.get('content').length === 0) return null if (status.get('content').length === 0) return null
@ -302,7 +307,7 @@ class StatusContent extends ImmutablePureComponent {
onMouseUp={this.handleMouseUp} onMouseUp={this.handleMouseUp}
/> />
{ {
this.state.collapsed && this.state.collapsed && collapsable &&
<Button <Button
isText isText
underlineOnHover underlineOnHover

View File

@ -69,6 +69,7 @@ export default class StatusMedia extends ImmutablePureComponent {
{Component => ( {Component => (
<Component <Component
inline inline
isComment={isComment}
preview={video.get('preview_url')} preview={video.get('preview_url')}
blurhash={video.get('blurhash')} blurhash={video.get('blurhash')}
src={video.get('url')} src={video.get('url')}
@ -90,6 +91,7 @@ export default class StatusMedia extends ImmutablePureComponent {
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMedia}> <Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMedia}>
{Component => ( {Component => (
<Component <Component
isComment={isComment}
reduced={isChild} reduced={isChild}
media={status.get('media_attachments')} media={status.get('media_attachments')}
sensitive={status.get('sensitive')} sensitive={status.get('sensitive')}
@ -110,6 +112,7 @@ export default class StatusMedia extends ImmutablePureComponent {
onOpenMedia={onOpenMedia} onOpenMedia={onOpenMedia}
cacheWidth={cacheWidth} cacheWidth={cacheWidth}
defaultWidth={defaultWidth} defaultWidth={defaultWidth}
isComment={isComment}
/> />
) )
} }

View File

@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
import { injectIntl, defineMessages } from 'react-intl' import { injectIntl, defineMessages } from 'react-intl'
import { me } from '../initial_state' import { me } from '../initial_state'
import ComposeFormContainer from '../features/compose/containers/compose_form_container' import ComposeFormContainer from '../features/compose/containers/compose_form_container'
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
import Avatar from './avatar' import Avatar from './avatar'
import Block from './block' import Block from './block'
import Heading from './heading' import Heading from './heading'
@ -52,7 +53,10 @@ class TimelineComposeBlock extends ImmutablePureComponent {
return ( return (
<section className={[_s.default, _s.mb15].join(' ')}> <section className={[_s.default, _s.mb15].join(' ')}>
<Block> <ResponsiveClassesComponent
classNames={[_s.default, _s.boxShadowBlock, _s.bgPrimary, _s.overflowHidden, _s.radiusSmall].join(' ')}
classNamesXS={[_s.default, _s.boxShadowBlock, _s.bgPrimary, _s.overflowHidden].join(' ')}
>
<div className={[_s.default, _s.bgSubtle, _s.borderTop1PX, _s.borderBottom1PX, _s.borderColorSecondary, _s.px15, _s.py2, _s.alignItemsCenter, _s.flexRow].join(' ')}> <div className={[_s.default, _s.bgSubtle, _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} noHover /> <Avatar account={account} size={20} noHover />
@ -62,7 +66,7 @@ class TimelineComposeBlock extends ImmutablePureComponent {
</Heading> </Heading>
</div> </div>
<ComposeFormContainer {...rest} /> <ComposeFormContainer {...rest} />
</Block> </ResponsiveClassesComponent>
</section> </section>
) )
} }

View File

@ -80,11 +80,13 @@ const makeMapStateToProps = () => {
username: username, username: username,
}) })
let fetchedContext = false
let descendantsIds = ImmutableList() let descendantsIds = ImmutableList()
let ancestorStatus let ancestorStatus
let fetchedContext = false //
if (status && status.get('in_reply_to_account_id')) {
if (status && status.get('in_reply_to_account_id') && !props.isChild) {
fetchedContext = true fetchedContext = true
let inReplyTos = state.getIn(['contexts', 'inReplyTos']) let inReplyTos = state.getIn(['contexts', 'inReplyTos'])
@ -100,12 +102,16 @@ const makeMapStateToProps = () => {
}) })
const ancestorStatusId = ancestorsIds.get(0) const ancestorStatusId = ancestorsIds.get(0)
ancestorStatus = getStatus(state, { if (ancestorStatusId !== statusId) {
id: ancestorStatusId, ancestorStatus = getStatus(state, {
}) id: ancestorStatusId,
descendantsIds = getDescendants(state, ancestorStatus, statusId) })
descendantsIds = getDescendants(state, ancestorStatus, statusId)
}
} }
//
if (status && status.get('replies_count') > 0 && !fetchedContext) { if (status && status.get('replies_count') > 0 && !fetchedContext) {
descendantsIds = getDescendants(state, status) descendantsIds = getDescendants(state, status)
} }

View File

@ -277,8 +277,6 @@ class ComposeForm extends ImmutablePureComponent {
displayNone: length(this.props.text) === 0 || anyMedia, displayNone: length(this.props.text) === 0 || anyMedia,
}) })
console.log("reduxReplyToId:", reduxReplyToId, shouldCondense, isModalOpen)
return ( return (
<div className={parentContainerClasses}> <div className={parentContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.width100PC].join(' ')}> <div className={[_s.default, _s.flexRow, _s.width100PC].join(' ')}>

View File

@ -52,7 +52,6 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(changeGroupDescription(value)) dispatch(changeGroupDescription(value))
}, },
onCoverImageChange: (imageData) => { onCoverImageChange: (imageData) => {
console.log("imageData:", imageData)
dispatch(changeGroupCoverImage(imageData)) dispatch(changeGroupCoverImage(imageData))
}, },
onResetEditor: () => { onResetEditor: () => {

View File

@ -0,0 +1,76 @@
import {
BREAKPOINT_EXTRA_LARGE,
BREAKPOINT_LARGE,
BREAKPOINT_MEDIUM,
BREAKPOINT_SMALL,
BREAKPOINT_EXTRA_SMALL,
} from '../../../constants'
import { getWindowDimension } from '../../../utils/is_mobile'
const initialState = getWindowDimension()
export default class ResponsiveClassesComponent extends PureComponent {
static propTypes = {
classNames: PropTypes.string,
classNamesXL: PropTypes.string,
classNamesLarge: PropTypes.string,
classNamesMedium: PropTypes.string,
classNamesSmall: PropTypes.string,
classNamesXS: PropTypes.string,
}
state = {
width: initialState.width,
}
componentDidMount() {
this.handleResize()
window.addEventListener('resize', this.handleResize, false)
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize, false)
}
handleResize = () => {
const { width } = getWindowDimension()
this.setState({ width })
}
render() {
const {
children,
classNames,
classNamesXL,
classNamesLarge,
classNamesMedium,
classNamesSmall,
classNamesXS,
} = this.props
const { width } = this.state
let classes;
if (width >= BREAKPOINT_EXTRA_LARGE) {
classes = classNamesXL || classNames
} else if (width < BREAKPOINT_EXTRA_LARGE && width >= BREAKPOINT_LARGE) {
classes = classNames //default
} else if (width < BREAKPOINT_LARGE && width >= BREAKPOINT_MEDIUM) {
classes = classNamesLarge || classNames
} else if (width < BREAKPOINT_MEDIUM && width >= BREAKPOINT_SMALL) {
classes = classNamesMedium || classNamesLarge || classNames
} else if (width < BREAKPOINT_SMALL && width >= BREAKPOINT_EXTRA_SMALL) {
classes = classNamesSmall || classNamesMedium || classNamesLarge || classNames
} else {
classes = classNamesXS || classNamesSmall || classNamesMedium || classNamesLarge || classNames
}
return (
<div className={classes}>
{children}
</div>
)
}
}

View File

@ -3,6 +3,7 @@ import { getWindowDimension } from '../../../utils/is_mobile'
const initialState = getWindowDimension() const initialState = getWindowDimension()
export default class Responsive extends PureComponent { export default class Responsive extends PureComponent {
static propTypes = { static propTypes = {
min: PropTypes.number, min: PropTypes.number,
max: PropTypes.number, max: PropTypes.number,
@ -18,6 +19,7 @@ export default class Responsive extends PureComponent {
} }
componentDidMount() { componentDidMount() {
this.handleResize()
window.addEventListener('resize', this.handleResize, false) window.addEventListener('resize', this.handleResize, false)
} }
@ -43,4 +45,5 @@ export default class Responsive extends PureComponent {
return shouldRender ? children : null return shouldRender ? children : null
} }
} }

View File

@ -2,10 +2,10 @@ import Sticky from 'react-stickynode'
import Sidebar from '../components/sidebar' import Sidebar from '../components/sidebar'
import { BREAKPOINT_EXTRA_SMALL } from '../constants' import { BREAKPOINT_EXTRA_SMALL } from '../constants'
import NavigationBar from '../components/navigation_bar' import NavigationBar from '../components/navigation_bar'
// : todo : import FooterBar from '../components/footer_bar'
// import Footer from '../components/footer'
import FloatingActionButton from '../components/floating_action_button' import FloatingActionButton from '../components/floating_action_button'
import Responsive from '../features/ui/util/responsive_component' import Responsive from '../features/ui/util/responsive_component'
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
export default class Layout extends PureComponent { export default class Layout extends PureComponent {
@ -56,47 +56,56 @@ export default class Layout extends PureComponent {
</Responsive> </Responsive>
} }
<main role='main' className={[_s.default, _s.flexShrink1, _s.flexGrow1].join(' ')}> <ResponsiveClassesComponent
classNames={[_s.default, _s.flexShrink1, _s.flexGrow1].join(' ')}
classNamesSmall={[_s.default, _s.width100PC].join(' ')}
>
<main role='main'>
<div className={[_s.default, _s.width1015PX, _s.flexRow, _s.justifyContentEnd, _s.py15].join(' ')}> <div className={[_s.default, _s.width1015PX, _s.flexRow, _s.justifyContentEnd, _s.py15].join(' ')}>
{ {
noRightSidebar && children noRightSidebar && children
} }
{ {
!noRightSidebar && !noRightSidebar &&
<div className={[_s.default, _s.width645PX, _s.z1].join(' ')}> <div className={[_s.default, _s.width645PX, _s.z1].join(' ')}>
<div className={_s.default}> <div className={_s.default}>
{children} {children}
</div>
</div> </div>
</div> }
}
{ {
!noRightSidebar && !noRightSidebar &&
<Responsive min={BREAKPOINT_EXTRA_SMALL}> <Responsive min={BREAKPOINT_EXTRA_SMALL}>
<div className={[_s.default, _s.width340PX, _s.ml15].join(' ')}> <div className={[_s.default, _s.width340PX, _s.ml15].join(' ')}>
<Sticky top={73} enabled> <Sticky top={73} enabled>
<div className={[_s.default, _s.width340PX].join(' ')}> <div className={[_s.default, _s.width340PX].join(' ')}>
{layout} {layout}
</div> </div>
</Sticky> </Sticky>
</div> </div>
</Responsive> </Responsive>
} }
{ {
!noComposeButton && !noComposeButton &&
<Responsive max={BREAKPOINT_EXTRA_SMALL}> <Responsive max={BREAKPOINT_EXTRA_SMALL}>
<FloatingActionButton /> <FloatingActionButton />
</Responsive> </Responsive>
} }
</div> </div>
</main> </main>
</ResponsiveClassesComponent>
</div> </div>
<Responsive max={BREAKPOINT_EXTRA_SMALL}>
<FooterBar title={title} />
</Responsive>
</div> </div>
) )
} }

View File

@ -78,16 +78,13 @@ export const makeGetStatus = () => {
], ],
(state, statusBase, quotedStatus, statusRepost, accountBase, accountQuoted, accountRepost, username, filters) => { (state, statusBase, quotedStatus, statusRepost, accountBase, accountQuoted, accountRepost, username, filters) => {
console.log("statusBase:", statusBase)
if (!statusBase) { if (!statusBase) {
console.log("return null 1")
return null return null
} }
const accountUsername = accountBase.get('acct'); const accountUsername = accountBase.get('acct');
//Must be owner of status if username exists //Must be owner of status if username exists
if (accountUsername !== username && username !== undefined) { if (accountUsername !== username && username !== undefined) {
console.log("return null 2")
return null return null
} }

View File

@ -1,12 +1,13 @@
'use strict' 'use strict'
import detectPassiveEvents from 'detect-passive-events' import detectPassiveEvents from 'detect-passive-events'
import {
const BREAKPOINT_EXTRA_LARGE = 1480 BREAKPOINT_EXTRA_LARGE,
const BREAKPOINT_LARGE = 1280 BREAKPOINT_LARGE,
const BREAKPOINT_MEDIUM = 1160 BREAKPOINT_MEDIUM,
const BREAKPOINT_SMALL = 1080 BREAKPOINT_SMALL,
const BREAKPOINT_EXTRA_SMALL = 992 BREAKPOINT_EXTRA_SMALL,
} from '../constants'
const LAYOUT_BREAKPOINT = 630 const LAYOUT_BREAKPOINT = 630
@ -34,20 +35,6 @@ export function breakpointExtraSmall(width) {
return width < BREAKPOINT_EXTRA_SMALL return width < BREAKPOINT_EXTRA_SMALL
} }
export function getScreenBreakpoint(width) {
if (width > BREAKPOINT_EXTRA_LARGE) {
return 'BREAKPOINT_EXTRA_LARGE'
} else if (width > BREAKPOINT_MEDIUM && width < BREAKPOINT_LARGE) {
return 'BREAKPOINT_LARGE'
} else if (width > BREAKPOINT_SMALL && width < BREAKPOINT_MEDIUM) {
return 'BREAKPOINT_MEDIUM'
} else if (width > BREAKPOINT_EXTRA_SMALL && width < BREAKPOINT_SMALL) {
return 'BREAKPOINT_SMALL'
} else {
return 'BREAKPOINT_EXTRA_SMALL'
}
}
export const getWindowDimension = () => { export const getWindowDimension = () => {
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
const height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight const height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight

View File

@ -228,6 +228,7 @@ body {
.alignItemsCenter { align-items: center; } .alignItemsCenter { align-items: center; }
.justifyContentSpaceBetween { justify-content: space-between; } .justifyContentSpaceBetween { justify-content: space-between; }
.justifyContentSpaceAround { justify-content: space-around; }
.justifyContentCenter { justify-content: center; } .justifyContentCenter { justify-content: center; }
.justifyContentEnd { justify-content: flex-end; } .justifyContentEnd { justify-content: flex-end; }
@ -390,6 +391,7 @@ body {
.top50PC { top: 50%; } .top50PC { top: 50%; }
.bottom0 { bottom: 0; } .bottom0 { bottom: 0; }
.bottom50PX { bottom: 50px; }
.bottomAuto { bottom: auto; } .bottomAuto { bottom: auto; }
.left0 { left: 0px; } .left0 { left: 0px; }
@ -504,6 +506,10 @@ body {
.width240PX { .width240PX {
width: 230px; width: 230px;
} }
.width1255PX {
width: 1140px;
}
} }
@media (min-width: 1080px) and (max-width: 1160px) { @media (min-width: 1080px) and (max-width: 1160px) {
@ -522,6 +528,10 @@ body {
.width240PX { .width240PX {
width: 210px; width: 210px;
} }
.width1255PX {
width: 1060px;
}
} }
@media (min-width: 992px) and (max-width: 1080px) { @media (min-width: 992px) and (max-width: 1080px) {
@ -540,6 +550,10 @@ body {
.width240PX { .width240PX {
width: 100px; width: 100px;
} }
.width1255PX {
width: 950px;
}
} }
@media (min-width: 0px) and (max-width: 992px) { @media (min-width: 0px) and (max-width: 992px) {
@ -562,6 +576,10 @@ body {
.width240PX { .width240PX {
width: 0px; width: 0px;
} }
.width1255PX {
width: 100%;
}
} }
.textAlignLeft { text-align: left; } .textAlignLeft { text-align: left; }