This commit is contained in:
mgabdev
2020-12-15 19:31:30 -05:00
parent de0c977950
commit 75d52c841e
129 changed files with 2559 additions and 910 deletions

View File

@@ -189,6 +189,7 @@ class AutosuggestTextbox extends ImmutablePureComponent {
id,
isPro,
isEdit,
isModalOpen,
} = this.props
const { suggestionsHidden } = this.state

View File

@@ -1,29 +1,24 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {
FormattedMessage,
defineMessages,
injectIntl,
} from 'react-intl'
import { openModal } from '../actions/modal'
import {
me,
repository,
source_url,
me,
} from '../initial_state'
import { CX, DEFAULT_REL } from '../constants'
import { DEFAULT_REL } from '../constants'
import Text from './text'
import Button from './button'
import DotTextSeperator from './dot_text_seperator'
class LinkFooter extends React.PureComponent {
render() {
const {
intl,
noPadding,
onOpenHotkeys,
} = this.props
const { intl } = this.props
const currentYear = new Date().getFullYear()
@@ -32,12 +27,6 @@ class LinkFooter extends React.PureComponent {
href: 'https://help.gab.com',
text: intl.formatMessage(messages.help),
},
// : todo :
// {
// onClick: onOpenHotkeys,
// text: intl.formatMessage(messages.hotkeys),
// requiresUser: true,
// },
{
href: '/auth/edit',
text: intl.formatMessage(messages.security),
@@ -52,16 +41,16 @@ class LinkFooter extends React.PureComponent {
text: intl.formatMessage(messages.investors),
},
{
to: '/about/tos',
text: intl.formatMessage(messages.terms),
to: '/about/sales',
text: intl.formatMessage(messages.salesTerms),
},
{
to: '/about/dmca',
text: intl.formatMessage(messages.dmca),
},
{
to: '/about/sales',
text: intl.formatMessage(messages.salesTerms),
to: '/about/tos',
text: intl.formatMessage(messages.terms),
},
{
to: '/about/privacy',
@@ -75,36 +64,33 @@ class LinkFooter extends React.PureComponent {
},
]
const containerClasses = CX({
d: 1,
px10: !noPadding,
mb15: 1,
})
return (
<div className={containerClasses}>
<div className={[_s.d, _s.mb15].join(' ')}>
<nav aria-label='Footer' role='navigation' className={[_s.d, _s.flexWrap, _s.flexRow].join(' ')}>
{
linkFooterItems.map((linkFooterItem, i) => {
if (linkFooterItem.requiresUser && !me) return null
return (
<Button
isText
underlineOnHover
color='none'
backgroundColor='none'
key={`link-footer-item-${i}`}
to={linkFooterItem.to}
href={linkFooterItem.href}
data-method={linkFooterItem.logout ? 'delete' : null}
onClick={linkFooterItem.onClick || null}
className={[_s.mt5, _s.mb5, _s.pr15].join(' ')}
>
<Text size='small' color='tertiary'>
{linkFooterItem.text}
</Text>
</Button>
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.jcCenter].join(' ')}>
<Button
isText
underlineOnHover
color='none'
backgroundColor='none'
key={`link-footer-item-${i}`}
to={linkFooterItem.to}
href={linkFooterItem.href}
data-method={linkFooterItem.logout ? 'delete' : null}
onClick={linkFooterItem.onClick || null}
className={[_s.mt5].join(' ')}
>
<Text size='small' color='tertiary'>
{linkFooterItem.text}
</Text>
</Button>
{ !linkFooterItem.logout && <Text size='small' color='secondary' className={[_s.pt2, _s.mr5, _s.ml5].join(' ')}>·</Text> }
</div>
)
})
}
@@ -120,7 +106,7 @@ class LinkFooter extends React.PureComponent {
defaultMessage='Gab Social is open source software. You can contribute or report issues on our self-hosted GitLab at {gitlab}.'
values={{
gitlab: (
<a href={source_url} className={[_s.displayBlock, _s.inherit].join(' ')} rel={DEFAULT_REL} target='_blank'>
<a href={source_url} className={[_s.displayInlineBlock, _s.inherit].join(' ')} rel={DEFAULT_REL} target='_blank'>
{repository}
</a>
)
@@ -136,8 +122,6 @@ class LinkFooter extends React.PureComponent {
const messages = defineMessages({
investors: { id: 'getting_started.investors', defaultMessage: 'Investors' },
help: { id: 'getting_started.help', defaultMessage: 'Help' },
invite: { id: 'getting_started.invite', defaultMessage: 'Invite people' },
hotkeys: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Hotkeys' },
security: { id: 'getting_started.security', defaultMessage: 'Security' },
about: { id: 'navigation_bar.info', defaultMessage: 'About' },
developers: { id: 'getting_started.developers', defaultMessage: 'Developers' },
@@ -148,16 +132,8 @@ const messages = defineMessages({
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenHotkeys() {
dispatch(openModal('HOTKEYS'))
},
})
LinkFooter.propTypes = {
intl: PropTypes.object.isRequired,
noPadding: PropTypes.bool,
onOpenHotkeys: PropTypes.func.isRequired,
}
export default injectIntl(connect(null, mapDispatchToProps)(LinkFooter))
export default injectIntl(LinkFooter)

View File

@@ -79,7 +79,7 @@ class MediaItem extends ImmutablePureComponent {
posAbs: 1,
top0: 1,
h100PC: 1,
w100PC: 1,
// w100PC: 1,
py2: !isSmall,
px2: !isSmall,
})
@@ -87,7 +87,7 @@ class MediaItem extends ImmutablePureComponent {
const linkClasses = CX({
d: 1,
w100PC: 1,
h100PC: 1,
// h100PC: 1,
overflowHidden: 1,
border1PX: 1,
borderColorPrimary: 1,
@@ -96,7 +96,7 @@ class MediaItem extends ImmutablePureComponent {
const statusUrl = `/${account.getIn(['acct'])}/posts/${status.get('id')}`;
return (
<div className={[_s.d, _s.w25PC, _s.pt25PC].join(' ')}>
<div className={[_s.d, _s.pt25PC].join(' ')}>
<div className={containerClasses}>
<NavLink
to={statusUrl}
@@ -117,6 +117,7 @@ class MediaItem extends ImmutablePureComponent {
visible &&
<Image
height='100%'
width=''
src={attachment.get('preview_url')}
alt={attachment.get('description')}
title={attachment.get('description')}

View File

@@ -49,9 +49,9 @@ class ComposeModal extends ImmutablePureComponent {
const title = isEditing ? messages.edit : isComment ? messages.comment : messages.title
return (
<div style={{width: '512px'}} className={[_s.d, _s.modal].join(' ')}>
<div style={{width: '580px'}} className={[_s.d, _s.modal].join(' ')}>
<Block>
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.jcCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.h53PX, _s.pl10, _s.pr15].join(' ')}>
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.jcCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.h53PX, _s.pl5, _s.pr10].join(' ')}>
<div className={[_s.d, _s.w115PX, _s.aiStart, _s.jcCenter, _s.mrAuto].join(' ')}>
<Button
backgroundColor='none'
@@ -69,8 +69,8 @@ class ComposeModal extends ImmutablePureComponent {
<ComposeFormSubmitButton type='header' />
</div>
</div>
<div className={[_s.d].join(' ')}>
<TimelineComposeBlock isModal />
<div className={[_s.d, _s.pt5].join(' ')}>
<TimelineComposeBlock isModal formLocation='modal' />
</div>
</Block>
</div>

View File

@@ -1,6 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { MODAL_DECK_COLUMN_ADD_OPTIONS } from '../../constants'
import { setDeckColumnAtIndex } from '../../actions/deck'
import { openModal } from '../../actions/modal'
import ModalLayout from './modal_layout'
@@ -10,27 +11,19 @@ import Text from '../text'
class DeckColumnAddModal extends React.PureComponent {
onAdd = (column) => {
console.log("onAdd column: ", column)
switch (column) {
case 'user':
//
break
case 'list':
//
break
case 'group':
//
break
case 'hashtag':
//
break
default:
this.props.dispatch(setDeckColumnAtIndex(column))
this.props.onClose()
break
const moreOptions = ['user', 'list', 'group', 'hashtag']
if (moreOptions.indexOf(column) > -1) {
this.openOptionsModal(column)
} else {
this.props.dispatch(setDeckColumnAtIndex(column))
this.props.onClose()
}
}
openOptionsModal = (column) => {
this.props.dispatch(openModal(MODAL_DECK_COLUMN_ADD_OPTIONS, { column }))
}
render() {
const {
intl,

View File

@@ -0,0 +1,75 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { openModal } from '../../actions/modal'
import { MODAL_DECK_COLUMN_ADD } from '../../constants'
import Heading from '../heading'
import Button from '../button'
import Block from '../block'
class DeckColumnAddOptionsModal extends React.PureComponent {
state = {
selectedItem: null,
}
onClickClose = () => {
this.props.onClose()
this.props.dispatch(openModal(MODAL_DECK_COLUMN_ADD))
}
handleAdd = () => {
//
}
render() {
const { column } = this.props
const { selectedItem } = this.state
// user, hashtag, list, groups
if (!column) return <div />
const title = `Select a ${column}`
return (
<div style={{width: '520px'}} className={[_s.d, _s.modal].join(' ')}>
<Block>
<div className={[_s.d, _s.flexRow, _s.aiCenter, _s.jcCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.h53PX, _s.pl10, _s.pr15].join(' ')}>
<div className={[_s.d, _s.w115PX, _s.aiStart, _s.jcCenter, _s.mrAuto].join(' ')}>
<Button
backgroundColor='none'
title='Back'
onClick={this.onClickClose}
color='secondary'
icon='back'
iconSize='16px'
/>
</div>
<Heading size='h2'>
{title}
</Heading>
<div className={[_s.d, _s.w115PX, _s.aiEnd, _s.jcCenter, _s.mlAuto].join(' ')}>
<Button
isDisabled={!selectedItem}
onClick={this.handleAdd}
>
Add
</Button>
</div>
</div>
<div className={[_s.d].join(' ')}>
test
</div>
</Block>
</div>
)
}
}
DeckColumnAddOptionsModal.propTypes = {
onClose: PropTypes.func.isRequired,
column: PropTypes.string.isRequired,
}
export default connect()(DeckColumnAddOptionsModal)

View File

@@ -16,6 +16,7 @@ import {
MODAL_COMPOSE,
MODAL_CONFIRM,
MODAL_DECK_COLUMN_ADD,
MODAL_DECK_COLUMN_ADD_OPTIONS,
MODAL_DISPLAY_OPTIONS,
MODAL_EDIT_PROFILE,
MODAL_EDIT_SHORTCUTS,
@@ -51,6 +52,7 @@ import {
ComposeModal,
ConfirmationModal,
DeckColumnAddModal,
DeckColumnAddOptionsModal,
DisplayOptionsModal,
EditProfileModal,
EditShortcutsModal,
@@ -89,6 +91,7 @@ const MODAL_COMPONENTS = {
[MODAL_COMPOSE]: ComposeModal,
[MODAL_CONFIRM]: ConfirmationModal,
[MODAL_DECK_COLUMN_ADD]: DeckColumnAddModal,
[MODAL_DECK_COLUMN_ADD_OPTIONS]: DeckColumnAddOptionsModal,
[MODAL_DISPLAY_OPTIONS]: DisplayOptionsModal,
[MODAL_EDIT_SHORTCUTS]: EditShortcutsModal,
[MODAL_EDIT_PROFILE]: EditProfileModal,

View File

@@ -49,7 +49,7 @@ class ChatNavigationBar extends React.PureComponent {
<div className={[_s.d, _s.h53PX, _s.flexRow, _s.jcCenter, _s.aiCenter, _s.mrAuto].join(' ')}>
<AvatarGroup accounts={otherAccounts} size={35} noHover />
<Heading size='h1'>
<div className={[_s.dangerousContent, _s.pl10, _s.fs19PX].join(' ')} dangerouslySetInnerHTML={{ __html: nameHTML }} />
<div className={[_s.dangerousContent, _s.colorNavigation, _s.pl10, _s.fs19PX].join(' ')} dangerouslySetInnerHTML={{ __html: nameHTML }} />
</Heading>
</div>

View File

@@ -8,7 +8,7 @@ import Heading from '../heading'
import Button from '../button'
import BackButton from '../back_button'
import Text from '../text'
import CharacterCounter from '../character_counter'
import ComposeFormSubmitButton from '../../features/compose/components/compose_form_submit_button'
class ComposeNavigationBar extends React.PureComponent {
@@ -26,13 +26,7 @@ class ComposeNavigationBar extends React.PureComponent {
} = this.props
const disabledButton = isSubmitting || isUploading || isChangingUpload || length(text) > MAX_POST_CHARACTER_COUNT || (length(text.trim()) === 0 && !anyMedia)
const buttonOptions = {
backgroundColor: disabledButton ? 'tertiary' : 'brand',
color: disabledButton ? 'tertiary' : 'white',
isDisabled: disabledButton,
onClick: this.handleOnPost,
}
return (
<div className={[_s.d, _s.z4, _s.h53PX, _s.w100PC].join(' ')}>
<div className={[_s.d, _s.h53PX, _s.bgNavigation, _s.aiCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')} >
@@ -48,18 +42,14 @@ class ComposeNavigationBar extends React.PureComponent {
<div className={[_s.d, _s.h53PX, _s.flexRow, _s.jcCenter, _s.aiCenter, _s.mrAuto].join(' ')}>
<Heading size='h1'>
Compose
<span className={[_s.dangerousContent, _s.fs24PX, _s.colorNavigation].join(' ')}>
Compose
</span>
</Heading>
</div>
<div className={[_s.d, _s.h53PX, _s.flexRow, _s.mlAuto, _s.aiCenter, _s.jcCenter, _s.mr15].join(' ')}>
<CharacterCounter max={MAX_POST_CHARACTER_COUNT} text={text} />
<Button {...buttonOptions}>
<Text color='inherit' weight='bold' size='medium' className={_s.px5}>
POST
</Text>
</Button>
<ComposeFormSubmitButton type='navigation' />
</div>
</div>

View File

@@ -61,7 +61,7 @@ class MediaGalleryPanel extends ImmutablePureComponent {
noPadding
title={intl.formatMessage(messages.title)}
headerButtonTitle={!!account ? intl.formatMessage(messages.show_all) : undefined}
headerButtonTo={!!account ? `/${account.get('acct')}/media` : undefined}
headerButtonTo={!!account ? `/${account.get('acct')}/photos` : undefined}
>
<div className={[_s.d, _s.flexRow, _s.flexWrap, _s.px10, _s.py10].join(' ')}>
{

View File

@@ -0,0 +1,135 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { defineMessages, injectIntl } from 'react-intl'
import { closePopover } from '../../actions/popover'
import { changeExpiresAt } from '../../actions/compose'
import {
EXPIRATION_OPTION_5_MINUTES,
EXPIRATION_OPTION_60_MINUTES,
EXPIRATION_OPTION_6_HOURS,
EXPIRATION_OPTION_24_HOURS,
EXPIRATION_OPTION_3_DAYS,
EXPIRATION_OPTION_7_DAYS,
} from '../../constants'
import PopoverLayout from './popover_layout'
import List from '../list'
class ChatConversationExpirationOptionsPopover extends React.PureComponent {
handleOnSetExpiration = (expiresAt) => {
this.props.onChangeExpiresAt(expiresAt)
this.handleOnClosePopover()
}
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() {
const {
expiresAtValue,
intl,
isXS,
} = this.props
const listItems = [
{
hideArrow: true,
title: 'None',
onClick: () => this.handleOnSetStatusExpiration(null),
isActive: !expiresAtValue,
},
{
hideArrow: true,
title: intl.formatMessage(messages.minutes, { number: 5 }),
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_5_MINUTES),
isActive: expiresAtValue === EXPIRATION_OPTION_5_MINUTES,
},
{
hideArrow: true,
title: intl.formatMessage(messages.minutes, { number: 60 }),
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_60_MINUTES),
isActive: expiresAtValue === EXPIRATION_OPTION_60_MINUTES,
},
{
hideArrow: true,
title: '6 hours',
title: intl.formatMessage(messages.hours, { number: 6 }),
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_6_HOURS),
isActive: expiresAtValue === EXPIRATION_OPTION_6_HOURS,
},
{
hideArrow: true,
title: intl.formatMessage(messages.hours, { number: 24 }),
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_24_HOURS),
isActive: expiresAtValue === EXPIRATION_OPTION_24_HOURS,
},
{
hideArrow: true,
title: '3 days',
title: intl.formatMessage(messages.days, { number: 3 }),
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_3_DAYS),
isActive: expiresAtValue === EXPIRATION_OPTION_3_DAYS,
},
{
hideArrow: true,
title: intl.formatMessage(messages.days, { number: 7 }),
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_7_DAYS),
isActive: expiresAtValue === EXPIRATION_OPTION_7_DAYS,
},
]
if (expiresAtValue) {
listItems.unshift({
hideArrow: true,
title: 'Remove expiration',
onClick: () => this.handleOnSetStatusExpiration(null),
},)
}
return (
<PopoverLayout
width={210}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<Text className={[_s.d, _s.px15, _s.py10, _s.bgSecondary].join(' ')}>This chats delete after:</Text>
<List
scrollKey='chat_conversation_expiration'
items={listItems}
size={isXS ? 'large' : 'small'}
/>
</PopoverLayout>
)
}
}
const messages = defineMessages({
minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },
days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
})
const mapStateToProps = (state) => ({
expiresAtValue: state.getIn(['compose', 'expires_at']),
})
const mapDispatchToProps = (dispatch) => ({
onChangeExpiresAt(expiresAt) {
dispatch(changeExpiresAt(expiresAt))
},
onClosePopover() {
dispatch(closePopover())
},
})
ChatConversationExpirationOptionsPopover.defaultProps = {
expiresAtValue: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
isXS: PropTypes.bool,
onChangeExpiresAt: PropTypes.func.isRequired,
}
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ChatConversationExpirationOptionsPopover))

View File

@@ -5,14 +5,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
import { connect } from 'react-redux'
import { closePopover } from '../../actions/popover'
import { openModal } from '../../actions/modal'
import {
isChatMessengerBlocked,
isChatMessengerMuted,
blockChatMessenger,
unblockChatMessenger,
muteChatMessenger,
unmuteChatMessenger,
} from '../../actions/chat_conversation_accounts'
import { hideChatConversation } from '../../actions/chat_conversations'
import { purgeChatMessages } from '../../actions/chat_messages'
import { MODAL_PRO_UPGRADE } from '../../constants'
import { me } from '../../initial_state'
import { makeGetChatConversation } from '../../selectors'
@@ -27,21 +21,6 @@ class ChatConversationOptionsPopover extends ImmutablePureComponent {
this.handleOnClosePopover()
}
handleOnBlock = () => {
this.props.onBlock()
this.handleOnClosePopover()
}
handleOnUnblock = () => {
this.props.onUnblock()
this.handleOnClosePopover()
}
handleOnMute = () => {
this.props.onMute()
this.handleOnClosePopover()
}
handleOnUnmute = () => {
this.props.onUnute()
this.handleOnClosePopover()
@@ -51,7 +30,7 @@ class ChatConversationOptionsPopover extends ImmutablePureComponent {
if (!this.props.isPro) {
this.props.openProUpgradeModal()
} else {
this.props.onPurge()
this.props.onPurge(this.props.chatConversationId)
}
this.handleOnClosePopover()
@@ -68,18 +47,6 @@ class ChatConversationOptionsPopover extends ImmutablePureComponent {
} = this.props
const items = [
{
hideArrow: true,
title: 'Block Messenger',
subtitle: 'The messenger will not be able to message you.',
onClick: () => this.handleOnBlock(),
},
{
hideArrow: true,
title: 'Mute Messenger',
subtitle: 'You will not be notified of new messsages',
onClick: () => this.handleOnMute(),
},
{
hideArrow: true,
title: 'Hide Conversation',
@@ -123,6 +90,12 @@ const mapDispatchToProps = (dispatch) => ({
onSetCommentSortingSetting(type) {
dispatch(closePopover())
},
onPurge(chatConversationId) {
dispatch(purgeChatMessages(chatConversationId))
},
onHide(chatConversationId) {
dispatch(hideChatConversation(chatConversationId))
},
onClosePopover: () => dispatch(closePopover()),
})

View File

@@ -1,58 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { closePopover } from '../../actions/popover'
import { deleteChatMessage } from '../../actions/chat_messages'
import PopoverLayout from './popover_layout'
import Button from '../button'
import Text from '../text'
class ChatMessageDeletePopover extends React.PureComponent {
handleOnClick = () => {
this.props.onDeleteChatMessage(this.props.chatMessageId)
}
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() {
const { isXS } = this.props
return (
<PopoverLayout
width={96}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<Button
onClick={this.handleOnClick}
color='primary'
backgroundColor='tertiary'
className={[_s.radiusSmall].join(' ')}
>
<Text align='center' color='inherit'>Remove</Text>
</Button>
</PopoverLayout>
)
}
}
const mapDispatchToProps = (dispatch) => ({
onDeleteChatMessage(chatMessageId) {
dispatch(deleteChatMessage(chatMessageId))
dispatch(closePopover())
},
onClosePopover() {
dispatch(closePopover())
},
})
ChatMessageDeletePopover.propTypes = {
isXS: PropTypes.bool,
chatMessageId: PropTypes.string.isRequired,
onDeleteChatMessage: PropTypes.func.isRequired,
}
export default connect(null, mapDispatchToProps)(ChatMessageDeletePopover)

View File

@@ -0,0 +1,139 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { closePopover } from '../../actions/popover'
import { deleteChatMessage } from '../../actions/chat_messages'
import {
isChatMessengerBlocked,
isChatMessengerMuted,
blockChatMessenger,
unblockChatMessenger,
muteChatMessenger,
unmuteChatMessenger,
reportChatMessage,
} from '../../actions/chat_conversation_accounts'
import { makeGetChatMessage } from '../../selectors'
import { me } from '../../initial_state'
import PopoverLayout from './popover_layout'
import Button from '../button'
import List from '../list'
import Text from '../text'
class ChatMessageOptionsPopover extends React.PureComponent {
handleOnDelete = () => {
this.props.onDeleteChatMessage(this.props.chatMessageId)
}
handleOnReport = () => {
this.props.onReportChatMessage(this.props.chatMessageId)
}
handleOnBlock = () => {
if (this.props.isBlocked) {
this.props.unblockChatMessenger(this.props.fromAccountId)
} else {
this.props.blockChatMessenger(this.props.fromAccountId)
}
}
handleOnMute = () => {
if (this.props.isMuted) {
this.props.unmuteChatMessenger(this.props.fromAccountId)
} else {
this.props.muteChatMessenger(this.props.fromAccountId)
}
}
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() {
const {
isXS,
isMine,
isMuted,
isBlocked,
} = this.props
const items = isMine ? [
{
hideArrow: true,
title: 'Delete Message',
onClick: () => this.handleOnDelete(),
}
] : [
{
hideArrow: true,
title: 'Report Messenger',
onClick: () => this.handleOnReport(),
},
{},
{
hideArrow: true,
title: isBlocked ? 'Unblock Messenger' : 'Block Messenger',
subtitle: isBlocked ? '' : 'The messenger will not be able to message you.',
onClick: () => this.handleOnBlock(),
},
{
hideArrow: true,
title: isMuted ? 'Unmute Messenger' : 'Mute Messenger',
subtitle: isMuted ? '' : 'You will not be notified of new messsages',
onClick: () => this.handleOnMute(),
},
]
return (
<PopoverLayout
width={isMine ? 160 : 200}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<List items={items} />
</PopoverLayout>
)
}
}
const mapStateToProps = (state, { chatMessageId }) => ({
isMine: state.getIn(['chat_messages', chatMessageId, 'from_account_id']) === me,
fromAccountId: state.getIn(['chat_messages', chatMessageId, 'from_account_id']),
isBlocked: state.getIn(['chat_messages', chatMessageId, 'from_account_id']),
isMuted: state.getIn(['chat_messages', chatMessageId, 'from_account_id']),
})
const mapDispatchToProps = (dispatch) => ({
onDeleteChatMessage(chatMessageId) {
dispatch(deleteChatMessage(chatMessageId))
dispatch(closePopover())
},
onBlock(accountId) {
dispatch(blockChatMessenger(accountId))
},
onUnblock(accountId) {
dispatch(unblockChatMessenger(accountId))
},
onMute(accountId) {
dispatch(muteChatMessenger(accountId))
},
onUnmute(accountId) {
dispatch(unmuteChatMessenger(accountId))
},
onReportChatMessage(chatMessageId) {
dispatch(reportChatMessage(chatMessageId))
},
onClosePopover() {
dispatch(closePopover())
},
})
ChatMessageOptionsPopover.propTypes = {
isXS: PropTypes.bool,
chatMessageId: PropTypes.string.isRequired,
isBlocked: PropTypes.bool.isRequired,
isMuted: PropTypes.bool.isRequired,
onDeleteChatMessage: PropTypes.func.isRequired,
}
export default connect(mapStateToProps, mapDispatchToProps)(ChatMessageOptionsPopover)

View File

@@ -0,0 +1,61 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { closePopover } from '../../actions/popover'
import PopoverLayout from './popover_layout'
import List from '../list'
import Text from '../text'
class ComposePostDesinationPopover extends React.PureComponent {
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() {
const {
isXS,
} = this.props
// TIMELINE
// GROUP - MY GROUPS
const items = [
{
hideArrow: true,
title: 'Timeline',
onClick: () => this.handleOnDelete(),
},
{
title: 'Group',
onClick: () => this.handleOnReport(),
},
]
return (
<PopoverLayout
width={180}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<Text className={[_s.d, _s.px15, _s.py10, _s.bgSecondary].join(' ')}>Post to:</Text>
<List items={items} />
</PopoverLayout>
)
}
}
const mapStateToProps = (state) => ({
//
})
const mapDispatchToProps = (dispatch) => ({
onClosePopover: () => dispatch(closePopover()),
})
ComposePostDesinationPopover.propTypes = {
isXS: PropTypes.bool,
onClosePopover: PropTypes.func.isRequired,
}
export default connect(mapStateToProps, mapDispatchToProps)(ComposePostDesinationPopover)

View File

@@ -1,8 +1,9 @@
import {
BREAKPOINT_EXTRA_SMALL,
POPOVER_CHAT_CONVERSATION_OPTIONS,
POPOVER_CHAT_MESSAGE_DELETE,
POPOVER_CHAT_MESSAGE_OPTIONS,
POPOVER_COMMENT_SORTING_OPTIONS,
POPOVER_COMPOSE_POST_DESTINATION,
POPOVER_DATE_PICKER,
POPOVER_EMOJI_PICKER,
POPOVER_GROUP_LIST_SORT_OPTIONS,
@@ -23,8 +24,9 @@ import {
} from '../../constants'
import {
ChatConversationOptionsPopover,
ChatMessageDeletePopover,
ChatMessageOptionsPopover,
CommentSortingOptionsPopover,
ComposePostDesinationPopover,
DatePickerPopover,
EmojiPickerPopover,
GroupListSortOptionsPopover,
@@ -59,8 +61,9 @@ const initialState = getWindowDimension()
const POPOVER_COMPONENTS = {
[POPOVER_CHAT_CONVERSATION_OPTIONS]: ChatConversationOptionsPopover,
[POPOVER_CHAT_MESSAGE_DELETE]: ChatMessageDeletePopover,
[POPOVER_CHAT_MESSAGE_OPTIONS]: ChatMessageOptionsPopover,
[POPOVER_COMMENT_SORTING_OPTIONS]: CommentSortingOptionsPopover,
[POPOVER_COMPOSE_POST_DESTINATION]: ComposePostDesinationPopover,
[POPOVER_DATE_PICKER]: DatePickerPopover,
[POPOVER_EMOJI_PICKER]: EmojiPickerPopover,
[POPOVER_GROUP_LIST_SORT_OPTIONS]: GroupListSortOptionsPopover,

View File

@@ -5,15 +5,16 @@ import { defineMessages, injectIntl } from 'react-intl'
import { closePopover } from '../../actions/popover'
import { changeExpiresAt } from '../../actions/compose'
import {
STATUS_EXPIRATION_OPTION_5_MINUTES,
STATUS_EXPIRATION_OPTION_60_MINUTES,
STATUS_EXPIRATION_OPTION_6_HOURS,
STATUS_EXPIRATION_OPTION_24_HOURS,
STATUS_EXPIRATION_OPTION_3_DAYS,
STATUS_EXPIRATION_OPTION_7_DAYS,
EXPIRATION_OPTION_5_MINUTES,
EXPIRATION_OPTION_60_MINUTES,
EXPIRATION_OPTION_6_HOURS,
EXPIRATION_OPTION_24_HOURS,
EXPIRATION_OPTION_3_DAYS,
EXPIRATION_OPTION_7_DAYS,
} from '../../constants'
import PopoverLayout from './popover_layout'
import List from '../list'
import Text from '../text'
class StatusExpirationOptionsPopover extends React.PureComponent {
@@ -34,43 +35,49 @@ class StatusExpirationOptionsPopover extends React.PureComponent {
} = this.props
const listItems = [
{
hideArrow: true,
title: 'None',
onClick: () => this.handleOnSetStatusExpiration(null),
isActive: !expiresAtValue,
},
{
hideArrow: true,
title: intl.formatMessage(messages.minutes, { number: 5 }),
onClick: () => this.handleOnSetStatusExpiration(STATUS_EXPIRATION_OPTION_5_MINUTES),
isActive: expiresAtValue === STATUS_EXPIRATION_OPTION_5_MINUTES,
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_5_MINUTES),
isActive: expiresAtValue === EXPIRATION_OPTION_5_MINUTES,
},
{
hideArrow: true,
title: intl.formatMessage(messages.minutes, { number: 60 }),
onClick: () => this.handleOnSetStatusExpiration(STATUS_EXPIRATION_OPTION_60_MINUTES),
isActive: expiresAtValue === STATUS_EXPIRATION_OPTION_60_MINUTES,
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_60_MINUTES),
isActive: expiresAtValue === EXPIRATION_OPTION_60_MINUTES,
},
{
hideArrow: true,
title: '6 hours',
title: intl.formatMessage(messages.hours, { number: 6 }),
onClick: () => this.handleOnSetStatusExpiration(STATUS_EXPIRATION_OPTION_6_HOURS),
isActive: expiresAtValue === STATUS_EXPIRATION_OPTION_6_HOURS,
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_6_HOURS),
isActive: expiresAtValue === EXPIRATION_OPTION_6_HOURS,
},
{
hideArrow: true,
title: intl.formatMessage(messages.hours, { number: 24 }),
onClick: () => this.handleOnSetStatusExpiration(STATUS_EXPIRATION_OPTION_24_HOURS),
isActive: expiresAtValue === STATUS_EXPIRATION_OPTION_24_HOURS,
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_24_HOURS),
isActive: expiresAtValue === EXPIRATION_OPTION_24_HOURS,
},
{
hideArrow: true,
title: '3 days',
title: intl.formatMessage(messages.days, { number: 3 }),
onClick: () => this.handleOnSetStatusExpiration(STATUS_EXPIRATION_OPTION_3_DAYS),
isActive: expiresAtValue === STATUS_EXPIRATION_OPTION_3_DAYS,
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_3_DAYS),
isActive: expiresAtValue === EXPIRATION_OPTION_3_DAYS,
},
{
hideArrow: true,
title: intl.formatMessage(messages.days, { number: 7 }),
onClick: () => this.handleOnSetStatusExpiration(STATUS_EXPIRATION_OPTION_7_DAYS),
isActive: expiresAtValue === STATUS_EXPIRATION_OPTION_7_DAYS,
onClick: () => this.handleOnSetStatusExpiration(EXPIRATION_OPTION_7_DAYS),
isActive: expiresAtValue === EXPIRATION_OPTION_7_DAYS,
},
]
@@ -88,8 +95,9 @@ class StatusExpirationOptionsPopover extends React.PureComponent {
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<Text className={[_s.d, _s.px15, _s.py10, _s.bgSecondary].join(' ')}>This gab deletes after:</Text>
<List
scrollKey='group_list_sort_options'
scrollKey='status_expiration'
items={listItems}
size={isXS ? 'large' : 'small'}
/>

View File

@@ -5,6 +5,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
import { connect } from 'react-redux'
import { defineMessages, injectIntl } from 'react-intl'
import { openModal } from '../../actions/modal'
import { showToast } from '../../actions/toasts'
import { closePopover } from '../../actions/popover'
import PopoverLayout from './popover_layout'
import Button from '../button'
@@ -31,6 +32,7 @@ class StatusSharePopover extends ImmutablePureComponent {
}
document.body.removeChild(textarea)
this.props.onShowCopyToast()
this.handleClosePopover()
}
@@ -157,6 +159,9 @@ const messages = defineMessages({
const mapDispatchToProps = (dispatch) => ({
onClosePopover: () => dispatch(closePopover()),
onShowCopyToast() {
dispatch(showToast())
},
})
StatusSharePopover.propTypes = {

View File

@@ -49,6 +49,7 @@ class StatusVisibilityDropdown extends React.PureComponent {
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<Text className={[_s.d, _s.px15, _s.py10, _s.bgSecondary].join(' ')}>Status Visibility:</Text>
<div className={[_s.d].join(' ')}>
{
options.map((option, i) => {

View File

@@ -148,7 +148,7 @@ class StyleButton extends React.PureComponent {
px10: 1,
mr5: 1,
noSelect: 1,
bgSecondaryDark_onHover: 1,
bgSubtle_onHover: 1,
bgBrandLight: active,
bgTransparent: 1,
radiusSmall: 1,
@@ -162,7 +162,7 @@ class StyleButton extends React.PureComponent {
onMouseDown={this.handleOnClick}
title={label}
>
<Icon id={icon} size='12px' className={_s[iconColor]} />
<Icon id={icon} size='16px' className={_s[iconColor]} />
</button>
)
}

View File

@@ -43,12 +43,16 @@ class DeckSidebar extends ImmutablePureComponent {
this.props.onOpenComposeModal()
}
scrollToItem = () => {
}
setAvatarNode = (c) => {
this.avatarNode = c
}
render() {
const { account, logoDisabled } = this.props
const { account, gabDeckOrder, logoDisabled } = this.props
const isPro = !!account ? account.get('is_pro') : false
@@ -83,6 +87,22 @@ class DeckSidebar extends ImmutablePureComponent {
<Divider isSmall />
<div className={[_s.d, _s.aiCenter, _s.jcCenter].join(' ')}>
{
!!gabDeckOrder && gabDeckOrder.map((item, i) => (
<Button
isText
key={`gab-deck-sidebar-dot-${i}`}
onClick={this.scrollToItem}
backgroundColor='secondary'
className={[_s.mt5, _s.mb5, _s.px10, _s.py10, _s.circle].join(' ')}
icon='notifications'
iconClassName={_s.cPrimary}
/>
))
}
</div>
<Divider isSmall />
{ isPro && <NavigationBarButton title='&nbsp;' icon='add' onClick={this.handleOnOpenNewColumnModel} /> }
@@ -119,6 +139,7 @@ const mapStateToProps = (state) => ({
account: makeGetAccount()(state, me),
theme: state.getIn(['settings', 'displayOptions', 'theme'], DEFAULT_THEME),
logoDisabled: state.getIn(['settings', 'displayOptions', 'logoDisabled'], false),
gabDeckOrder: state.getIn(['settings', 'gabDeckOrder']),
})
const mapDispatchToProps = (dispatch) => ({

View File

@@ -10,12 +10,14 @@ import ComposeFormContainer from '../features/compose/containers/compose_form_co
import ResponsiveClassesComponent from '../features/ui/util/responsive_classes_component'
import Responsive from '../features/ui/util/responsive_component'
import Avatar from './avatar'
import Heading from './heading'
import Button from './button'
import Text from './text'
class TimelineComposeBlock extends ImmutablePureComponent {
render() {
const {
formLocation,
account,
size,
intl,
@@ -27,7 +29,7 @@ class TimelineComposeBlock extends ImmutablePureComponent {
return (
<section className={_s.d}>
<div className={[_s.d, _s.flexRow].join(' ')}>
<ComposeFormContainer {...rest} isModal={isModal} />
<ComposeFormContainer {...rest} isModal={isModal} formLocation={formLocation} />
</div>
</section>
)
@@ -39,17 +41,7 @@ class TimelineComposeBlock extends ImmutablePureComponent {
classNames={[_s.d, _s.boxShadowBlock, _s.bgPrimary, _s.overflowHidden, _s.radiusSmall].join(' ')}
classNamesXS={[_s.d, _s.boxShadowBlock, _s.bgPrimary, _s.overflowHidden].join(' ')}
>
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
<div className={[_s.d, _s.bgSubtle, _s.borderTop1PX, _s.borderBottom1PX, _s.borderColorSecondary, _s.px15, _s.py2, _s.aiCenter, _s.flexRow].join(' ')}>
<div className={_s.mr10}>
<Avatar account={account} size={20} noHover />
</div>
<Heading size='h5'>
{intl.formatMessage(messages.createPost)}
</Heading>
</div>
</Responsive>
<ComposeFormContainer {...rest} />
<ComposeFormContainer {...rest} formLocation={formLocation} />
</ResponsiveClassesComponent>
</section>
)
@@ -70,10 +62,12 @@ TimelineComposeBlock.propTypes = {
account: ImmutablePropTypes.map.isRequired,
size: PropTypes.number,
isModal: PropTypes.bool,
formLocation: PropTypes.string,
}
TimelineComposeBlock.defaultProps = {
size: 32,
formLocation: 'timeline',
}
export default injectIntl(connect(mapStateToProps)(TimelineComposeBlock))

View File

@@ -344,7 +344,7 @@ class Video extends ImmutablePureComponent {
this.video.play()
}
setTimeout(() => { // : hack :
this.video.requestPictureInPicture()
this.video.requestPictureInPicture()
}, 500)
} else {
document.exitPictureInPicture()