Progess on Gab Deck
Progess on Gab Deck
This commit is contained in:
parent
998f00ae48
commit
bb7348fc61
@ -11,12 +11,19 @@ class DeckColumn extends React.PureComponent {
|
||||
icon,
|
||||
children,
|
||||
index,
|
||||
noButtons,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.w360PX, _s.px2, _s.bgSecondary, _s.h100VH].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.bgPrimary, _s.h100VH].join(' ')}>
|
||||
<DeckColumnHeader title={title} subtitle={subtitle} icon={icon} index={index} />
|
||||
<DeckColumnHeader
|
||||
title={title}
|
||||
subtitle={subtitle}
|
||||
icon={icon}
|
||||
index={index}
|
||||
noButtons={noButtons}
|
||||
/>
|
||||
<div className={[_s.d, _s.w100PC, _s.overflowYScroll, _s.boxShadowNone, _s.posAbs, _s.top60PX, _s.left0, _s.right0, _s.bottom0].join(' ')}>
|
||||
{children}
|
||||
</div>
|
||||
@ -32,6 +39,7 @@ DeckColumn.propTypes = {
|
||||
subtitle: PropTypes.string,
|
||||
icon: PropTypes.string,
|
||||
index: PropTypes.number,
|
||||
noButtons: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default DeckColumn
|
@ -22,6 +22,7 @@ class DeckColumnHeader extends React.PureComponent {
|
||||
subtitle,
|
||||
icon,
|
||||
children,
|
||||
noButtons,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
@ -40,7 +41,7 @@ class DeckColumnHeader extends React.PureComponent {
|
||||
{ !!subtitle && <Text className={_s.ml5} color='secondary'>{subtitle}</Text> }
|
||||
</div>
|
||||
{
|
||||
!!title &&
|
||||
!!title && !noButtons &&
|
||||
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.mlAuto, _s.jcCenter].join(' ')}>
|
||||
<Button
|
||||
isNarrow
|
||||
@ -71,6 +72,7 @@ DeckColumnHeader.propTypes = {
|
||||
subtitle: PropTypes.string,
|
||||
icon: PropTypes.string,
|
||||
index: PropTypes.number,
|
||||
noButtons: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default connect()(DeckColumnHeader)
|
@ -21,6 +21,9 @@ class DeckColumnAddModal extends React.PureComponent {
|
||||
case 'group':
|
||||
//
|
||||
break
|
||||
case 'hashtag':
|
||||
//
|
||||
break
|
||||
default:
|
||||
this.props.dispatch(setDeckColumnAtIndex(column))
|
||||
this.props.onClose()
|
||||
@ -51,11 +54,16 @@ class DeckColumnAddModal extends React.PureComponent {
|
||||
<DeckColumnAddModalButton icon='like' type='Likes' onClick={() => this.onAdd('likes')} />
|
||||
<DeckColumnAddModalButton icon='bookmark' type='Bookmarks' onClick={() => this.onAdd('bookmarks')} />
|
||||
</div>
|
||||
<div className={[_s.d, _s.pl10, _s.pb10, _s.flexRow, _s.aiCenter, _s.jcCenter].join(' ')}>
|
||||
<div className={[_s.d, _s.pl10, _s.borderBottom1PX, _s.borderColorSecondary, _s.flexRow, _s.aiCenter, _s.jcCenter].join(' ')}>
|
||||
<DeckColumnAddModalButton icon='pro' type='PRO Timeline' onClick={() => this.onAdd('pro')} />
|
||||
<DeckColumnAddModalButton icon='pencil' type='Compose' onClick={() => this.onAdd('compose')} />
|
||||
<DeckColumnAddModalButton icon='group' type='Group Timeline' onClick={() => this.onAdd('group')} />
|
||||
</div>
|
||||
<div className={[_s.d, _s.pl10, _s.pb10, _s.flexRow, _s.aiCenter, _s.jcCenter].join(' ')}>
|
||||
<DeckColumnAddModalButton icon='apps' type='Hashtag' onClick={() => this.onAdd('hashtag')} />
|
||||
<DeckColumnAddModalButton icon='explore' type='Explore' onClick={() => this.onAdd('explore')} />
|
||||
<DeckColumnAddModalButton icon='news' type='News' onClick={() => this.onAdd('news')} />
|
||||
</div>
|
||||
</div>
|
||||
</ModalLayout>
|
||||
)
|
||||
|
@ -50,6 +50,8 @@ class DeckSidebar extends ImmutablePureComponent {
|
||||
render() {
|
||||
const { account, logoDisabled } = this.props
|
||||
|
||||
const isPro = !!account ? account.get('is_pro') : false
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.z4, _s.w76PX, _s.w100PC].join(' ')}>
|
||||
|
||||
@ -83,7 +85,7 @@ class DeckSidebar extends ImmutablePureComponent {
|
||||
|
||||
<Divider isSmall />
|
||||
|
||||
<NavigationBarButton title=' ' icon='add' onClick={this.handleOnOpenNewColumnModel} />
|
||||
{ isPro && <NavigationBarButton title=' ' icon='add' onClick={this.handleOnOpenNewColumnModel} /> }
|
||||
</div>
|
||||
|
||||
<div className={[_s.d, _s.mtAuto, _s.aiCenter].join(' ')}>
|
||||
|
@ -166,7 +166,8 @@ export const TIMELINE_INJECTION_WEIGHT_MULTIPLIER = 100
|
||||
export const TIMELINE_INJECTION_WEIGHT_SUBTRACTOR = 0.005
|
||||
export const TIMELINE_INJECTION_WEIGHT_MIN = 0.01
|
||||
|
||||
export const GAB_DECK_OPTIONS = ['home', 'user.id', 'notifications', 'list.id', 'likes', 'bookmarks', 'pro', 'compose', 'group.id']
|
||||
export const GAB_DECK_MAX_ITEMS = 8
|
||||
export const GAB_DECK_OPTIONS = ['home', 'user.id', 'notifications', 'list.id', 'likes', 'bookmarks', 'pro', 'compose', 'group.id', 'explore', 'news', 'news.id', 'hashtag.id']
|
||||
|
||||
export const TRENDS_RSS_SOURCES = [
|
||||
{'id':'5daf64b18e955e2433b0f5ce','title':'Breitbart'},
|
||||
|
@ -8,16 +8,20 @@ import {
|
||||
sortableElement,
|
||||
} from 'react-sortable-hoc'
|
||||
import { me, meUsername} from '../initial_state'
|
||||
import {
|
||||
GAB_DECK_MAX_ITEMS,
|
||||
MODAL_PRO_UPGRADE,
|
||||
} from '../constants'
|
||||
import {
|
||||
deckConnect,
|
||||
deckDisconnect,
|
||||
updateDeckColumnAtIndex,
|
||||
} from '../actions/deck'
|
||||
import {
|
||||
saveSettings,
|
||||
} from '../actions/settings'
|
||||
import { saveSettings } from '../actions/settings'
|
||||
import { openModal } from '../actions/modal'
|
||||
import WrappedBundle from './ui/util/wrapped_bundle'
|
||||
import DeckColumn from '../components/deck_column'
|
||||
import Text from '../components/text'
|
||||
import {
|
||||
AccountTimeline,
|
||||
Compose,
|
||||
@ -27,6 +31,8 @@ import {
|
||||
HashtagTimeline,
|
||||
BookmarkedStatuses,
|
||||
ProTimeline,
|
||||
News,
|
||||
ExploreTimeline,
|
||||
} from './ui/util/async_components'
|
||||
|
||||
class Deck extends React.PureComponent {
|
||||
@ -35,22 +41,21 @@ class Deck extends React.PureComponent {
|
||||
router: PropTypes.object,
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.props.connectDeck()
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.disconnectDeck()
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.props.dispatch(deckConnect())
|
||||
console.log("this.props.isPro:", this.props)
|
||||
if (!this.props.isPro) this.handleOnOpenProUpgradeModal()
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.dispatch(deckDisconnect())
|
||||
}
|
||||
|
||||
handleOnOpenProUpgradeModal = () => {
|
||||
console.log("handleOnOpenProUpgradeModal")
|
||||
this.props.dispatch(openModal(MODAL_PRO_UPGRADE))
|
||||
}
|
||||
|
||||
onSortEnd = ({oldIndex, newIndex}) => {
|
||||
this.props.dispatch(updateDeckColumnAtIndex(oldIndex, newIndex))
|
||||
}
|
||||
@ -66,7 +71,7 @@ class Deck extends React.PureComponent {
|
||||
}
|
||||
|
||||
getDeckColumn = (deckColumn, index) => {
|
||||
if (!deckColumn) return null
|
||||
if (!deckColumn || !isPro) return null
|
||||
|
||||
let Component = null
|
||||
let componentParams = {}
|
||||
@ -105,10 +110,22 @@ class Deck extends React.PureComponent {
|
||||
icon = 'pro'
|
||||
Component = ProTimeline
|
||||
break
|
||||
case 'news':
|
||||
title = 'News'
|
||||
icon = 'news'
|
||||
Component = News
|
||||
componentParams = { isSmall: true }
|
||||
break
|
||||
case 'explore':
|
||||
title = 'Explore'
|
||||
icon = 'explore'
|
||||
Component = ExploreTimeline
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// : todo :
|
||||
if (!Component) {
|
||||
if (deckColumn.indexOf('user.') > -1) {
|
||||
|
||||
@ -116,6 +133,10 @@ class Deck extends React.PureComponent {
|
||||
|
||||
} else if (deckColumn.indexOf('group.') > -1) {
|
||||
|
||||
} else if (deckColumn.indexOf('news.') > -1) {
|
||||
|
||||
} else if (deckColumn.indexOf('hashtag.') > -1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,12 +156,9 @@ class Deck extends React.PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { gabDeckOrder } = this.props
|
||||
|
||||
console.log("gabDeckOrder:", gabDeckOrder)
|
||||
const { gabDeckOrder, isPro } = this.props
|
||||
|
||||
const isEmpty = gabDeckOrder.size === 0
|
||||
// : todo : max: 12
|
||||
|
||||
return (
|
||||
<SortableContainer
|
||||
@ -150,17 +168,27 @@ class Deck extends React.PureComponent {
|
||||
shouldCancelStart={this.onShouldCancelStart}
|
||||
>
|
||||
{
|
||||
isEmpty &&
|
||||
(isEmpty || !isPro) &&
|
||||
<React.Fragment>
|
||||
<DeckColumn title='Compose' icon='pencil'>
|
||||
<DeckColumn title='Compose' icon='pencil' noButtons>
|
||||
<WrappedBundle component={Compose} />
|
||||
</DeckColumn>
|
||||
{
|
||||
!isPro &&
|
||||
<DeckColumn title='Gab Deck for GabPRO' icon='pro' noButtons>
|
||||
<div className={[_s.d, _s.px15, _s.py15].join(' ')}>
|
||||
<Text>
|
||||
Gab Deck for GabPRO
|
||||
</Text>
|
||||
</div>
|
||||
</DeckColumn>
|
||||
}
|
||||
<DeckColumn />
|
||||
</React.Fragment>
|
||||
}
|
||||
{
|
||||
!isEmpty &&
|
||||
gabDeckOrder.map((deckOption, i) => this.getDeckColumn(deckOption, i))
|
||||
!isEmpty && isPro &&
|
||||
gabDeckOrder.splice(0, GAB_DECK_MAX_ITEMS).map((deckOption, i) => this.getDeckColumn(deckOption, i))
|
||||
}
|
||||
</SortableContainer>
|
||||
)
|
||||
@ -181,10 +209,12 @@ const SortableContainer = sortableContainer(({children}) => (
|
||||
))
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
isPro: state.getIn(['accounts', me, 'is_pro']),
|
||||
gabDeckOrder: state.getIn(['settings', 'gabDeckOrder']),
|
||||
})
|
||||
|
||||
Deck.propTypes = {
|
||||
isPro: PropTypes.bool.isRequired,
|
||||
gabDeckOrder: ImmutablePropTypes.list,
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(openPopover(POPOVER_CHAT_CONVERSATION_OPTIONS, {
|
||||
chatConversationId,
|
||||
targetRef,
|
||||
position: 'bottom',
|
||||
position: 'left-end',
|
||||
}))
|
||||
},
|
||||
})
|
||||
|
@ -11,8 +11,6 @@ import Button from '../components/button'
|
||||
import Text from '../components/text'
|
||||
import TrendsItem from '../components/trends_item'
|
||||
import PreviewCardItem from '../components/preview_card_item'
|
||||
import ResponsiveClassesComponent from './ui/util/responsive_classes_component'
|
||||
import Responsive from './ui/util/responsive_component'
|
||||
import WrappedBundle from './ui/util/wrapped_bundle'
|
||||
import {
|
||||
GabNewsPanel,
|
||||
@ -23,11 +21,15 @@ import {
|
||||
TrendsHeadlinesPanel,
|
||||
TrendsRSSPanel,
|
||||
} from './ui/util/async_components'
|
||||
import { getWindowDimension } from '../utils/is_mobile'
|
||||
|
||||
const initialState = getWindowDimension()
|
||||
|
||||
class News extends React.PureComponent {
|
||||
|
||||
state = {
|
||||
lazyLoaded: false,
|
||||
width: initialState.width,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -35,10 +37,22 @@ class News extends React.PureComponent {
|
||||
this.documentElement = document.scrollingElement || document.documentElement
|
||||
|
||||
this.window.addEventListener('scroll', this.handleScroll)
|
||||
|
||||
this.handleResize()
|
||||
window.addEventListener('keyup', this.handleKeyUp, false)
|
||||
window.addEventListener('resize', this.handleResize, false)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.detachScrollListener()
|
||||
window.removeEventListener('keyup', this.handleKeyUp)
|
||||
window.removeEventListener('resize', this.handleResize, false)
|
||||
}
|
||||
|
||||
handleResize = () => {
|
||||
const { width } = getWindowDimension()
|
||||
|
||||
this.setState({ width })
|
||||
}
|
||||
|
||||
detachScrollListener = () => {
|
||||
@ -57,56 +71,50 @@ class News extends React.PureComponent {
|
||||
}, 150, { trailing: true })
|
||||
|
||||
render() {
|
||||
const { children } = this.props
|
||||
const { lazyLoaded } = this.state
|
||||
const { children, isSmall } = this.props
|
||||
const { lazyLoaded, width } = this.state
|
||||
|
||||
// const orderXS = ['headlines', 'breaking', 'trending_links', 'latest_from_gab', 'gab_news', 'trends_feeds']
|
||||
const isXS = width <= BREAKPOINT_EXTRA_SMALL
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.d, _s.flexRow, _s.w100PC, _s.overflowHidden].join(' ')}
|
||||
classNamesXS={[_s.d, _s.pt15].join(' ')}
|
||||
>
|
||||
|
||||
<ResponsiveClassesComponent
|
||||
classNames={[_s.d, _s.pr15, _s.w50PC].join(' ')}
|
||||
classNamesXS={[_s.d, _s.w100PC].join(' ')}
|
||||
>
|
||||
{ /* DESKTOP */ }
|
||||
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
|
||||
<WrappedBundle component={TrendsHeadlinesPanel} />
|
||||
<WrappedBundle component={TrendsBreakingPanel} componentParams={{ hideReadMore: 1 }} />
|
||||
<WrappedBundle component={LatestFromGabPanel} componentParams={{ isLazy: true, shouldLoad: lazyLoaded }} />
|
||||
</Responsive>
|
||||
{ /* MOBILE */ }
|
||||
<Responsive max={BREAKPOINT_EXTRA_SMALL}>
|
||||
if (isXS || isSmall) {
|
||||
return (
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.pt15].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<WrappedBundle component={TrendsHeadlinesPanel} />
|
||||
<WrappedBundle component={TrendsBreakingPanel} componentParams={{ hideReadMore: 1 }} />
|
||||
<WrappedBundle component={PopularLinksPanel} componentParams={{ isLazy: true, shouldLoad: lazyLoaded }} />
|
||||
<WrappedBundle component={LatestFromGabPanel} componentParams={{ isLazy: true, shouldLoad: lazyLoaded }} />
|
||||
<WrappedBundle component={GabNewsPanel} componentParams={{ isLazy: true, shouldLoad: lazyLoaded }} />
|
||||
<WrappedBundle component={TrendsFeedsPanel} />
|
||||
</Responsive>
|
||||
</ResponsiveClassesComponent>
|
||||
|
||||
|
||||
{ /* DESKTOP */ }
|
||||
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
|
||||
<div classNames={[_s.d, _s.w50PC].join(' ')}>
|
||||
<WrappedBundle component={PopularLinksPanel} />
|
||||
<WrappedBundle component={TrendsFeedsPanel} />
|
||||
<WrappedBundle component={GabNewsPanel} componentParams={{ isLazy: true, shouldLoad: lazyLoaded }} />
|
||||
</div>
|
||||
</Responsive>
|
||||
|
||||
</ResponsiveClassesComponent>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.w100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.w100PC, _s.overflowHidden].join(' ')}>
|
||||
<div className={[_s.d, _s.pr15, _s.w50PC].join(' ')}>
|
||||
<WrappedBundle component={TrendsHeadlinesPanel} />
|
||||
<WrappedBundle component={TrendsBreakingPanel} componentParams={{ hideReadMore: 1 }} />
|
||||
<WrappedBundle component={LatestFromGabPanel} componentParams={{ isLazy: true, shouldLoad: lazyLoaded }} />
|
||||
</div>
|
||||
<div classNames={[_s.d, _s.w50PC].join(' ')}>
|
||||
<WrappedBundle component={PopularLinksPanel} />
|
||||
<WrappedBundle component={TrendsFeedsPanel} />
|
||||
<WrappedBundle component={GabNewsPanel} componentParams={{ isLazy: true, shouldLoad: lazyLoaded }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
News.propTypes = {
|
||||
isSmall: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default News
|
@ -18,6 +18,7 @@ import {
|
||||
TIMELINE_INJECTION_PWA,
|
||||
TIMELINE_INJECTION_SHOP,
|
||||
TIMELINE_INJECTION_USER_SUGGESTIONS,
|
||||
GAB_DECK_MAX_ITEMS,
|
||||
} from '../constants'
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'
|
||||
import uuid from '../utils/uuid'
|
||||
@ -92,9 +93,8 @@ export default function settings(state = initialState, action) {
|
||||
case LIST_DELETE_SUCCESS:
|
||||
return filterDeadListColumns(state, action.id)
|
||||
case DECK_SET_COLUMN_AT_INDEX:
|
||||
// : todo : max: 12
|
||||
const sizeOfDeck = state.get('gabDeckOrder', ImmutableList()).size
|
||||
const newIndex = Math.max(action.index || 0, sizeOfDeck)
|
||||
const newIndex = Math.min(Math.max(action.index || 0, sizeOfDeck), GAB_DECK_MAX_ITEMS)
|
||||
return state.setIn(['gabDeckOrder', newIndex + 1], action.column).set('saved', false)
|
||||
case DECK_DELETE_COLUMN_AT_INDEX:
|
||||
return state.deleteIn(['gabDeckOrder', action.index])
|
||||
|
@ -56,7 +56,7 @@
|
||||
"cssnano": "^4.1.10",
|
||||
"detect-passive-events": "^1.0.2",
|
||||
"dotenv": "^8.0.0",
|
||||
"draft-js": "^0.11.4",
|
||||
"draft-js": "^0.11.7",
|
||||
"draftjs-to-markdown": "^0.6.0",
|
||||
"emoji-mart": "Gargron/emoji-mart#build",
|
||||
"es6-symbol": "^3.1.1",
|
||||
@ -113,6 +113,7 @@
|
||||
"react-redux-loading-bar": "^4.0.8",
|
||||
"react-router-dom": "^4.1.1",
|
||||
"react-router-scroll-4": "^1.0.0-beta.2",
|
||||
"react-sortable-hoc": "^1.11.0",
|
||||
"react-stickynode": "^3.0.4",
|
||||
"react-swipeable-views": "^0.13.9",
|
||||
"react-textarea-autosize": "^7.1.0",
|
||||
|
Loading…
Reference in New Issue
Block a user