This commit is contained in:
mgabdev 2020-05-14 22:31:24 -04:00
parent 8d452f0f6b
commit 59466ccc08
15 changed files with 165 additions and 127 deletions

View File

@ -79,10 +79,6 @@ export function importFetchedStatuses(statuses) {
if (status.poll && status.poll.id) {
pushUnique(polls, normalizePoll(status.poll));
}
// if (status.replies_count > 0) {
// dispatch(fetchComments(status.id));
// }
}
statuses.forEach(processStatus);

View File

@ -189,8 +189,13 @@ export function deleteStatusFail(id, error) {
};
};
export function fetchContext(id) {
export function fetchContext(id, ensureIsReply) {
return (dispatch, getState) => {
if (ensureIsReply) {
const isReply = !!getState().getIn(['statuses', id, 'in_reply_to_id'], null)
if (!isReply) return;
}
dispatch(fetchContextRequest(id));
api(getState).get(`/api/v1/statuses/${id}/context`).then(response => {

View File

@ -259,7 +259,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
return (
<Fragment>
<div className={textareaContainerClasses}>
{/*<Textarea
<Textarea
inputRef={this.setTextbox}
className={textareaClasses}
disabled={disabled}
@ -273,9 +273,9 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
// onBlur={this.onBlur}
// onPaste={this.onPaste}
aria-autocomplete='list'
/>*/}
/>
<Composer
{/*<Composer
inputRef={this.setTextbox}
disabled={disabled}
placeholder={placeholder}
@ -288,7 +288,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
onBlur={this.onBlur}
onPaste={this.onPaste}
small={small}
/>
/>*/}
{children}
</div>

View File

@ -4,7 +4,8 @@ import {
CompositeDecorator,
RichUtils,
convertToRaw,
convertFromRaw
convertFromRaw,
ContentState,
} from 'draft-js'
import { draftToMarkdown } from 'markdown-draft-js'
// import draftToMarkdown from 'draftjs-to-markdown'
@ -115,6 +116,14 @@ class Composer extends PureComponent {
return null
}
componentDidUpdate (prevProps) {
// console.log("this.props.value:", this.props.value)
if (prevProps.value !== this.props.value) {
// const editorState = EditorState.push(this.state.editorState, ContentState.createFromText(this.props.value));
// this.setState({ editorState })
}
}
// EditorState.createWithContent(ContentState.createFromText('Hello'))
onChange = (editorState) => {
@ -122,17 +131,17 @@ class Composer extends PureComponent {
const content = this.state.editorState.getCurrentContent();
const text = content.getPlainText('\u0001')
const selectionState = editorState.getSelection()
const selectionStart = selectionState.getStartOffset()
// const selectionState = editorState.getSelection()
// const selectionStart = selectionState.getStartOffset()
const rawObject = convertToRaw(content);
const markdownString = draftToMarkdown(rawObject);
// const rawObject = convertToRaw(content);
// const markdownString = draftToMarkdown(rawObject);
// const markdownString = draftToMarkdown(rawObject, {
// trigger: '#',
// separator: ' ',
// });
console.log("markdownString:", markdownString)
// console.log("text:", text, this.props.value)
this.props.onChange(null, text, selectionStart, markdownString)
}

View File

@ -21,6 +21,10 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = (dispatch) => ({
onOpenSidebar() {
dispatch(openSidebar())
},
onOpenNavSettingsPopover() {
dispatch(openPopover())
}
})
@ -35,6 +39,7 @@ class NavigationBar extends ImmutablePureComponent {
title: PropTypes.string,
showBackBtn: PropTypes.bool,
onOpenSidebar: PropTypes.func.isRequired,
onOpenNavSettingsPopover: PropTypes.func.isRequired,
}
handleProfileClick = () => {

View File

@ -191,7 +191,9 @@ class EmojiPickerMenu extends ImmutablePureComponent {
include={categoriesSort}
recent={frequentlyUsedEmojis}
skin={skinTone}
emojiSize={24}
perLine={8}
emojiSize={22}
sheetSize={32}
set='twitter'
color='#30CE7D'
emoji=''

View File

@ -0,0 +1,65 @@
import { defineMessages, injectIntl } from 'react-intl'
import { MODAL_DISPLAY_OPTIONS } from '../../constants'
import { openModal } from '../../actions/modal'
import { closePopover } from '../../actions/popover'
import PopoverLayout from './popover_layout'
import List from '../list'
const messages = defineMessages({
display: { id: 'display_options', defaultMessage: 'Display Options' },
help: { id: 'getting_started.help', defaultMessage: 'Help' },
settings: { id: 'settings', defaultMessage: 'Settings' },
logout: { 'id': 'confirmations.logout.confirm', 'defaultMessage': 'Log out' },
})
const mapDispatchToProps = (dispatch) => ({
onOpenDisplayModal: () => {
dispatch(closePopover())
dispatch(openModal(MODAL_DISPLAY_OPTIONS))
},
})
export default
@injectIntl
@connect(null, mapDispatchToProps)
class NavSettingsPopover extends PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
onOpenDisplayModal: PropTypes.func.isRequired,
isXS: PropTypes.bool,
}
handleOnOpenDisplayModal = () => {
this.props.onOpenDisplayModal()
}
render() {
const { intl, isXS } = this.props
if (isXS) return null
return (
<PopoverLayout width={240}>
<List
size='large'
scrollKey='profile_options'
items={[
{
title: intl.formatMessage(messages.help),
href: 'https://help.gab.com',
},
{
title: intl.formatMessage(messages.settings),
href: '/settings/preferences',
},
{
title: intl.formatMessage(messages.logout),
href: '/auth/sign_out',
},
]}
/>
</PopoverLayout>
)
}
}

View File

@ -290,8 +290,6 @@ class ProfileOptionsPopover extends PureComponent {
handleBlockDomain = () => {
const domain = this.props.account.get('acct').split('@')[1]
console.log("handleBlockDomain:", domain)
// : todo : alert
if (!domain) return

View File

@ -38,6 +38,8 @@ const messages = defineMessages({
search: { id: 'tabs_bar.search', defaultMessage: 'Search' },
shop: { id: 'tabs_bar.shop', defaultMessage: 'Store - Buy Merch' },
chat: { id: 'tabs_bar.chat', defaultMessage: 'Chat' },
help: { id: 'getting_started.help', defaultMessage: 'Help' },
display: { id: 'display_options', defaultMessage: 'Display Options' },
})
const mapStateToProps = (state) => ({
@ -48,7 +50,8 @@ const mapStateToProps = (state) => ({
const mapDispatchToProps = (dispatch) => ({
onCloseSidebar: () => dispatch(closeSidebar()),
onOpenDisplayModel() {
dispatch(openModal())
dispatch(closeSidebar())
dispatch(openModal('DISPLAY_OPTIONS'))
}
})
@ -61,6 +64,7 @@ class SidebarXS extends ImmutablePureComponent {
account: ImmutablePropTypes.map,
sidebarOpen: PropTypes.bool,
onCloseSidebar: PropTypes.func.isRequired,
onOpenDisplayModel: PropTypes.func.isRequired,
}
componentDidUpdate () {
@ -87,13 +91,12 @@ class SidebarXS extends ImmutablePureComponent {
const mainItems = [
{
icon: 'user',
to: `/${acct}`,
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.profile),
},
{
icon: 'arrow-up',
icon: 'pro',
href: 'https://pro.gab.com',
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.pro),
@ -135,50 +138,45 @@ class SidebarXS extends ImmutablePureComponent {
title: intl.formatMessage(messages.lists),
},
{
icon: 'user',
icon: 'group',
to: '/follow_requests',
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.follow_requests),
},
{
icon: 'user',
icon: 'block',
to: '/blocks',
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.blocks),
},
{
icon: 'user',
icon: 'website',
to: '/domain_blocks',
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.domain_blocks),
},
{
icon: 'user',
icon: 'audio-mute',
to: '/mutes',
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.mutes),
},
{
icon: 'user',
icon: 'report',
to: '/filters',
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.filters),
},
{
// : todo :
icon: 'user',
onClick: this.handleSidebarClose, //on open display model
title: intl.formatMessage(messages.filters),
onClick: this.props.onOpenDisplayModel, //on open display model
title: intl.formatMessage(messages.display),
},
{
// : todo :
icon: 'user',
href: 'https://help.gab.com',
onClick: this.handleSidebarClose,
title: intl.formatMessage(messages.filters),
title: intl.formatMessage(messages.help),
},
{
icon: 'user',
href: '/auth/sign_out',
title: intl.formatMessage(messages.logout),
},

View File

@ -136,7 +136,7 @@ class Status extends ImmutablePureComponent {
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.isChild) return null
if (!nextProps.isHidden && (nextProps.isIntersecting || !nextProps.commentsLimited) && !prevState.loadedComments) {
return {
loadedComments: true
@ -159,7 +159,7 @@ class Status extends ImmutablePureComponent {
// timeline lazy loading comments
if (!prevState.loadedComments && this.state.loadedComments && this.props.status && !this.props.isChild) {
const commentCount = this.props.status.get('replies_count')
if (this.props.isComment) {
if (this.props.isComment && !this.props.ancestorStatus) {
this.props.onFetchContext(this.props.status.get('id'))
this._measureHeight(prevState.height !== this.state.height)
} else {
@ -381,7 +381,9 @@ class Status extends ImmutablePureComponent {
if (!status) return null
if (isComment && !ancestorStatus && !isChild) {
return <ColumnIndicator type='loading' />
// Wait to load...
// return <ColumnIndicator type='loading' />
return null
}
let reblogContent, rebloggedByText = null

View File

@ -4,6 +4,7 @@ import Button from './button'
import Text from './text'
export default class StatusActionBarItem extends PureComponent {
static propTypes = {
title: PropTypes.string.isRequired,
altTitle: PropTypes.string,
@ -80,4 +81,5 @@ export default class StatusActionBarItem extends PureComponent {
</div>
)
}
}

View File

@ -8,7 +8,10 @@ import debounce from 'lodash.debounce'
import { me, promotions } from '../initial_state';
import { dequeueTimeline } from '../actions/timelines';
import { scrollTopTimeline } from '../actions/timelines';
import { fetchStatus } from '../actions/statuses';
import {
fetchStatus,
fetchContext,
} from '../actions/statuses';
import StatusContainer from '../containers/status_container';
import ScrollableList from './scrollable_list';
import TimelineQueueButtonHeader from './timeline_queue_button_header';
@ -71,7 +74,10 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
}, 100),
fetchStatus(id) {
dispatch(fetchStatus(id));
}
},
onFetchContext(statusId) {
dispatch(fetchContext(statusId, true))
},
});
export default
@ -96,7 +102,12 @@ class StatusList extends ImmutablePureComponent {
promotion: PropTypes.object, // : todo :
promotedStatus: ImmutablePropTypes.map,
fetchStatus: PropTypes.func,
};
onFetchContext: PropTypes.func,
}
state = {
fetchedContext: false,
}
componentDidMount() {
this.handleDequeueTimeline();
@ -111,6 +122,15 @@ class StatusList extends ImmutablePureComponent {
}
}
fetchContextsForInitialStatuses = (statusIds) => {
console.log("fetchContextsForInitialStatuses:", statusIds)
for (let i = 0; i < statusIds.length; i++) {
const statusId = statusIds[i];
this.props.onFetchContext(statusId)
}
this.setState({ fetchedContext: true })
}
getFeaturedStatusCount = () => {
return this.props.featuredStatusIds ? this.props.featuredStatusIds.size : 0;
}
@ -180,11 +200,24 @@ class StatusList extends ImmutablePureComponent {
promotedStatus,
...other
} = this.props
const { fetchedContext } = this.state
if (isPartial) {
return <ColumnIndicator type='loading' />
}
// : hack :
// if index is 0 or 1 and is comment, preload context
if (statusIds && !fetchedContext) {
const firstStatusId = statusIds.get(0)
const secondStatusId = statusIds.get(1)
let arr = []
if (!!firstStatusId) arr.push(firstStatusId)
if (!!secondStatusId) arr.push(secondStatusId)
if (arr.length > 0) this.fetchContextsForInitialStatuses(arr)
}
let scrollableContent = (isLoading || statusIds.size > 0) ? (
statusIds.map((statusId, index) => statusId === null ? (
<div

View File

@ -320,9 +320,9 @@ class ComposeForm extends ImmutablePureComponent {
<div className={actionsContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
<EmojiPickerButton small={shouldCondense} isMatch={isMatch} />
{ /* <EmojiPickerButton small={shouldCondense} isMatch={isMatch} /> */ }
<UploadButton small={shouldCondense} />
{ /* <UploadButton small={shouldCondense} /> */ }
<div className={commentPublishBtnClasses}>
<Button
@ -452,7 +452,7 @@ class ComposeForm extends ImmutablePureComponent {
<div className={actionsContainerClasses}>
<div className={[_s.default, _s.flexRow, _s.mrAuto].join(' ')}>
<EmojiPickerButton small={shouldCondense} isMatch={isMatch} />
{ /* <EmojiPickerButton small={shouldCondense} isMatch={isMatch} /> */ }
<UploadButton small={shouldCondense} />
{ /* <GifSelectorButton small={shouldCondense} /> */}

View File

@ -1,91 +1,13 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl, defineMessages } from 'react-intl';
import spring from 'react-motion/lib/spring';
import {
changeComposing,
mountCompose,
unmountCompose,
} from '../../actions/compose';
import Motion from '../ui/util/optional_motion';
import ComposeFormContainer from './containers/compose_form_container';
import NavigationBar from './components/navigation_bar';
import elephantUIPlane from '../../../images/logo_ui_column_footer.png';
import ComposeFormContainer from './containers/compose_form_container'
const messages = defineMessages({
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Community feed' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new gab' },
});
const mapStateToProps = (state, ownProps) => ({
columns: state.getIn(['settings', 'columns']),
showSearch: ownProps.isSearchPage,
});
export default
@connect(mapStateToProps)
@injectIntl
class Compose extends ImmutablePureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
columns: ImmutablePropTypes.list.isRequired,
showSearch: PropTypes.bool,
isSearchPage: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
componentDidMount () {
const { isSearchPage } = this.props;
if (!isSearchPage) {
this.props.dispatch(mountCompose());
}
}
componentWillUnmount () {
const { isSearchPage } = this.props;
if (!isSearchPage) {
this.props.dispatch(unmountCompose());
}
}
onFocus = () => {
this.props.dispatch(changeComposing(true));
}
onBlur = () => {
this.props.dispatch(changeComposing(false));
}
export default class Compose extends PureComponent {
render () {
const { showSearch, isSearchPage, intl } = this.props;
const header = '';
return (
<div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>
{header}
{ /* isSearchPage && <SearchContainer /> */ }
<div className='drawer__pager'>
{!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
<NavigationBar onClose={this.onBlur} />
<ComposeFormContainer />
</div>}
</div>
<div className={[_s.default, _s.bgPrimary, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
<ComposeFormContainer />
</div>
);
)
}
}

View File

@ -41,6 +41,7 @@ import {
BlockedAccounts,
BlockedDomains,
CommunityTimeline,
Compose,
// Filters,
Followers,
Following,
@ -145,7 +146,7 @@ class SwitchingArea extends PureComponent {
<Redirect from='/' to='/home' exact />
<WrappedRoute path='/home' exact page={HomePage} component={HomeTimeline} content={children} />
<WrappedRoute path='/compose' exact page={CommunityPage} component={CommunityTimeline} content={children} />
<WrappedRoute path='/compose' exact page={BasicPage} component={Compose} content={children} componentParams={{ title: 'Gab' }} />
<WrappedRoute path='/timeline/all' exact page={CommunityPage} component={CommunityTimeline} content={children} componentParams={{ title: 'Community Feed' }} />