Column: remove top gap on mobile, implement pulling feedback

features-override
Alex Gleason 2021-11-03 20:35:40 -05:00
rodzic 9140e1daf0
commit 3e3433218c
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
17 zmienionych plików z 164 dodań i 77 usunięć

Wyświetl plik

@ -0,0 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import PullToRefresh from 'react-simple-pull-to-refresh';
/**
* Pullable:
* Basic "pull to refresh" without the refresh.
* Just visual feedback.
*/
export default class Pullable extends React.Component {
static propTypes = {
children: PropTypes.node.isRequired,
}
handleRefresh = () => {
return new Promise(resolve => resolve());
}
render() {
const { children } = this.props;
return (
<PullToRefresh
onRefresh={this.handleRefresh}
pullingContent={null}
refreshingContent={null}
>
{children}
</PullToRefresh>
);
}
}

Wyświetl plik

@ -7,7 +7,7 @@ import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../acti
import Icon from 'soapbox/components/icon'; import Icon from 'soapbox/components/icon';
import StatusList from '../../components/status_list'; import StatusList from '../../components/status_list';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column'; import Column from 'soapbox/components/column';
// import ColumnSettingsContainer from './containers/column_settings_container'; // import ColumnSettingsContainer from './containers/column_settings_container';
import SubNavigation from 'soapbox/components/sub_navigation'; import SubNavigation from 'soapbox/components/sub_navigation';
import { OrderedSet as ImmutableOrderedSet } from 'immutable'; import { OrderedSet as ImmutableOrderedSet } from 'immutable';

Wyświetl plik

@ -8,6 +8,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ChatList from './components/chat_list'; import ChatList from './components/chat_list';
import AudioToggle from 'soapbox/features/chats/components/audio_toggle'; import AudioToggle from 'soapbox/features/chats/components/audio_toggle';
import AccountSearch from 'soapbox/components/account_search'; import AccountSearch from 'soapbox/components/account_search';
import Pullable from 'soapbox/components/pullable';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'column.chats', defaultMessage: 'Chats' }, title: { id: 'column.chats', defaultMessage: 'Chats' },
@ -54,10 +55,12 @@ class ChatIndex extends React.PureComponent {
onSelected={this.handleSuggestion} onSelected={this.handleSuggestion}
/> />
<ChatList <Pullable>
onClickChat={this.handleClickChat} <ChatList
emptyMessage={<FormattedMessage id='chat_panels.main_window.empty' defaultMessage="No chats found. To start a chat, visit a user's profile." />} onClickChat={this.handleClickChat}
/> emptyMessage={<FormattedMessage id='chat_panels.main_window.empty' defaultMessage="No chats found. To start a chat, visit a user's profile." />}
/>
</Pullable>
</Column> </Column>
); );
} }

Wyświetl plik

@ -11,6 +11,7 @@ import ScrollableList from 'soapbox/components/scrollable_list';
import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder_account'; import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder_account';
import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder_hashtag'; import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder_hashtag';
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status'; import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
import Pullable from 'soapbox/components/pullable';
export default class SearchResults extends ImmutablePureComponent { export default class SearchResults extends ImmutablePureComponent {
@ -107,18 +108,20 @@ export default class SearchResults extends ImmutablePureComponent {
<FilterBar selectedFilter={selectedFilter} selectFilter={this.handleSelectFilter} /> <FilterBar selectedFilter={selectedFilter} selectFilter={this.handleSelectFilter} />
{noResultsMessage || ( {noResultsMessage || (
<ScrollableList <Pullable>
key={selectedFilter} <ScrollableList
scrollKey={`${selectedFilter}:${value}`} key={selectedFilter}
isLoading={submitted && !loaded} scrollKey={`${selectedFilter}:${value}`}
showLoading={submitted && !loaded && results.isEmpty()} isLoading={submitted && !loaded}
hasMore={hasMore} showLoading={submitted && !loaded && results.isEmpty()}
onLoadMore={this.handleLoadMore} hasMore={hasMore}
placeholderComponent={placeholderComponent} onLoadMore={this.handleLoadMore}
placeholderCount={20} placeholderComponent={placeholderComponent}
> placeholderCount={20}
{searchResults} >
</ScrollableList> {searchResults}
</ScrollableList>
</Pullable>
)} )}
</> </>
); );

Wyświetl plik

@ -21,6 +21,7 @@ import TimelineQueueButtonHeader from '../../components/timeline_queue_button_h
import { getSettings } from 'soapbox/actions/settings'; import { getSettings } from 'soapbox/actions/settings';
import PlaceholderNotification from 'soapbox/features/placeholder/components/placeholder_notification'; import PlaceholderNotification from 'soapbox/features/placeholder/components/placeholder_notification';
import SubNavigation from 'soapbox/components/sub_navigation'; import SubNavigation from 'soapbox/components/sub_navigation';
import Pullable from 'soapbox/components/pullable';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'column.notifications', defaultMessage: 'Notifications' }, title: { id: 'column.notifications', defaultMessage: 'Notifications' },
@ -188,7 +189,9 @@ class Notifications extends React.PureComponent {
count={totalQueuedNotificationsCount} count={totalQueuedNotificationsCount}
message={messages.queue} message={messages.queue}
/> />
{scrollContainer} <Pullable>
{scrollContainer}
</Pullable>
</Column> </Column>
); );
} }

Wyświetl plik

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Column from 'soapbox/components/column';
import ColumnHeader from 'soapbox/components/column_header'; import ColumnHeader from 'soapbox/components/column_header';
import SearchContainer from 'soapbox/features/compose/containers/search_container'; import SearchContainer from 'soapbox/features/compose/containers/search_container';
import SearchResultsContainer from 'soapbox/features/compose/containers/search_results_container'; import SearchResultsContainer from 'soapbox/features/compose/containers/search_results_container';
@ -10,11 +11,11 @@ const messages = defineMessages({
}); });
const Search = ({ intl }) => ( const Search = ({ intl }) => (
<div className='column search-page'> <Column className='search-page'>
<ColumnHeader icon='search' title={intl.formatMessage(messages.heading)} /> <ColumnHeader icon='search' title={intl.formatMessage(messages.heading)} />
<SearchContainer autoFocus autoSubmit /> <SearchContainer autoFocus autoSubmit />
<SearchResultsContainer /> <SearchResultsContainer />
</div> </Column>
); );
Search.propTypes = { Search.propTypes = {

Wyświetl plik

@ -8,7 +8,7 @@ import { fetchStatus } from '../../actions/statuses';
import MissingIndicator from '../../components/missing_indicator'; import MissingIndicator from '../../components/missing_indicator';
import DetailedStatus from './components/detailed_status'; import DetailedStatus from './components/detailed_status';
import ActionBar from './components/action_bar'; import ActionBar from './components/action_bar';
import Column from '../ui/components/column'; import Column from 'soapbox/components/column';
import { import {
favourite, favourite,
unfavourite, unfavourite,
@ -52,6 +52,7 @@ import ThreadStatus from './components/thread_status';
import PendingStatus from 'soapbox/features/ui/components/pending_status'; import PendingStatus from 'soapbox/features/ui/components/pending_status';
import SubNavigation from 'soapbox/components/sub_navigation'; import SubNavigation from 'soapbox/components/sub_navigation';
import { launchChat } from 'soapbox/actions/chats'; import { launchChat } from 'soapbox/actions/chats';
import Pullable from 'soapbox/components/pullable';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'status.title', defaultMessage: 'Post' }, title: { id: 'status.title', defaultMessage: 'Post' },
@ -626,56 +627,58 @@ class Status extends ImmutablePureComponent {
*/} */}
<div ref={this.setRef} className='thread'> <div ref={this.setRef} className='thread'>
{ancestors && ( <Pullable>
<div className='thread__ancestors'>{ancestors}</div> {ancestors && (
)} <div className='thread__ancestors'>{ancestors}</div>
)}
<div className='thread__status thread__status--focused'> <div className='thread__status thread__status--focused'>
<HotKeys handlers={handlers}> <HotKeys handlers={handlers}>
<div ref={this.setStatusRef} className={classNames('focusable', 'detailed-status__wrapper')} tabIndex='0' aria-label={textForScreenReader(intl, status, false)}> <div ref={this.setStatusRef} className={classNames('focusable', 'detailed-status__wrapper')} tabIndex='0' aria-label={textForScreenReader(intl, status, false)}>
<DetailedStatus <DetailedStatus
status={status} status={status}
onOpenVideo={this.handleOpenVideo} onOpenVideo={this.handleOpenVideo}
onOpenMedia={this.handleOpenMedia} onOpenMedia={this.handleOpenMedia}
onToggleHidden={this.handleToggleHidden} onToggleHidden={this.handleToggleHidden}
domain={domain} domain={domain}
showMedia={this.state.showMedia} showMedia={this.state.showMedia}
onToggleMediaVisibility={this.handleToggleMediaVisibility} onToggleMediaVisibility={this.handleToggleMediaVisibility}
/> />
<ActionBar <ActionBar
status={status} status={status}
onReply={this.handleReplyClick} onReply={this.handleReplyClick}
onFavourite={this.handleFavouriteClick} onFavourite={this.handleFavouriteClick}
onEmojiReact={this.handleEmojiReactClick} onEmojiReact={this.handleEmojiReactClick}
onReblog={this.handleReblogClick} onReblog={this.handleReblogClick}
onDelete={this.handleDeleteClick} onDelete={this.handleDeleteClick}
onDirect={this.handleDirectClick} onDirect={this.handleDirectClick}
onChat={this.handleChatClick} onChat={this.handleChatClick}
onMention={this.handleMentionClick} onMention={this.handleMentionClick}
onMute={this.handleMuteClick} onMute={this.handleMuteClick}
onMuteConversation={this.handleConversationMuteClick} onMuteConversation={this.handleConversationMuteClick}
onBlock={this.handleBlockClick} onBlock={this.handleBlockClick}
onReport={this.handleReport} onReport={this.handleReport}
onPin={this.handlePin} onPin={this.handlePin}
onBookmark={this.handleBookmark} onBookmark={this.handleBookmark}
onEmbed={this.handleEmbed} onEmbed={this.handleEmbed}
onDeactivateUser={this.handleDeactivateUser} onDeactivateUser={this.handleDeactivateUser}
onDeleteUser={this.handleDeleteUser} onDeleteUser={this.handleDeleteUser}
onToggleStatusSensitivity={this.handleToggleStatusSensitivity} onToggleStatusSensitivity={this.handleToggleStatusSensitivity}
onDeleteStatus={this.handleDeleteStatus} onDeleteStatus={this.handleDeleteStatus}
allowedEmoji={this.props.allowedEmoji} allowedEmoji={this.props.allowedEmoji}
emojiSelectorFocused={this.state.emojiSelectorFocused} emojiSelectorFocused={this.state.emojiSelectorFocused}
handleEmojiSelectorExpand={this.handleEmojiSelectorExpand} handleEmojiSelectorExpand={this.handleEmojiSelectorExpand}
handleEmojiSelectorUnfocus={this.handleEmojiSelectorUnfocus} handleEmojiSelectorUnfocus={this.handleEmojiSelectorUnfocus}
/> />
</div> </div>
</HotKeys> </HotKeys>
</div> </div>
{descendants && ( {descendants && (
<div className='thread__descendants'>{descendants}</div> <div className='thread__descendants'>{descendants}</div>
)} )}
</Pullable>
</div> </div>
</Column> </Column>
); );

Wyświetl plik

@ -2,6 +2,7 @@ import React from 'react';
import ColumnHeader from './column_header'; import ColumnHeader from './column_header';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Column from 'soapbox/components/column'; import Column from 'soapbox/components/column';
import Pullable from 'soapbox/components/pullable';
export default class UIColumn extends React.PureComponent { export default class UIColumn extends React.PureComponent {
@ -24,7 +25,9 @@ export default class UIColumn extends React.PureComponent {
return ( return (
<Column aria-labelledby={columnHeaderId} {...rest}> <Column aria-labelledby={columnHeaderId} {...rest}>
{heading && <ColumnHeader icon={icon} active={active} type={heading} columnHeaderId={columnHeaderId} showBackBtn={showBackBtn} />} {heading && <ColumnHeader icon={icon} active={active} type={heading} columnHeaderId={columnHeaderId} showBackBtn={showBackBtn} />}
{children} <Pullable>
{children}
</Pullable>
</Column> </Column>
); );
} }

Wyświetl plik

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Column from './column'; import Column from 'soapbox/components/column';
import ColumnHeader from '../../../components/column_header'; import ColumnHeader from '../../../components/column_header';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import LoadingIndicator from 'soapbox/components/loading_indicator'; import LoadingIndicator from 'soapbox/components/loading_indicator';

Wyświetl plik

@ -100,7 +100,7 @@ class ProfilePage extends ImmutablePureComponent {
</div> </div>
<div className='columns-area__panels__main'> <div className='columns-area__panels__main'>
<div className='columns-area'> <div className='columns-area '>
{children} {children}
</div> </div>
</div> </div>

Wyświetl plik

@ -127,7 +127,7 @@
display: block; display: block;
width: 100%; width: 100%;
max-width: 600px; max-width: 600px;
padding: 20px 20px 0; padding: 10px 0;
box-sizing: border-box; box-sizing: border-box;
.columns-area__panels__pane__inner { .columns-area__panels__pane__inner {

Wyświetl plik

@ -99,6 +99,10 @@
margin: 0 auto; margin: 0 auto;
padding-top: 15px; padding-top: 15px;
@media screen and (max-width: 580px) {
padding-top: 0;
}
.column { .column {
width: 100%; width: 100%;
padding: 0; padding: 0;
@ -124,7 +128,7 @@
@media (max-width: 580px) { @media (max-width: 580px) {
.timeline-compose-block { .timeline-compose-block {
border-radius: 0; border-radius: 0;
margin-top: -5px; margin-top: 10px;
} }
} }
@ -959,3 +963,18 @@
.sub-navigation + .account__section-headline { .sub-navigation + .account__section-headline {
background: var(--foreground-color); background: var(--foreground-color);
} }
// Pull to refresh
.columns-area .column {
.ptr,
.ptr__children {
background: var(--foreground-color);
}
&--transparent {
.ptr,
.ptr__children {
background: transparent;
}
}
}

Wyświetl plik

@ -103,10 +103,6 @@
padding: 10px 0; padding: 10px 0;
margin: 5px 0; margin: 5px 0;
@media screen and (max-width: 895px) {
border-bottom: 1px solid var(--brand-color--med);
}
a { a {
color: var(--highlight-text-color); color: var(--highlight-text-color);
} }

Wyświetl plik

@ -219,3 +219,13 @@
} }
} }
} }
// Pull to refresh
.lds-ellipsis div {
background: var(--primary-text-color--faint) !important;
}
.ptr,
.ptr__children {
overflow: visible !important;
}

Wyświetl plik

@ -765,3 +765,9 @@
background: var(--accent-color); background: var(--accent-color);
} }
} }
.page__top + .page__columns .columns-area {
@media screen and (max-width: 580px) {
padding-top: 10px;
}
}

Wyświetl plik

@ -132,6 +132,7 @@
"react-redux": "^7.2.5", "react-redux": "^7.2.5",
"react-router-dom": "^4.3.1", "react-router-dom": "^4.3.1",
"react-router-scroll-4": "^1.0.0-beta.1", "react-router-scroll-4": "^1.0.0-beta.1",
"react-simple-pull-to-refresh": "^1.3.0",
"react-sparklines": "^1.7.0", "react-sparklines": "^1.7.0",
"react-stickynode": "^4.0.0", "react-stickynode": "^4.0.0",
"react-swipeable-views": "^0.14.0", "react-swipeable-views": "^0.14.0",

Wyświetl plik

@ -7990,6 +7990,11 @@ react-side-effect@^2.1.0:
resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3" resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3"
integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ== integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==
react-simple-pull-to-refresh@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/react-simple-pull-to-refresh/-/react-simple-pull-to-refresh-1.3.0.tgz#5f7bcd475ea5c33ecd505d097b14f56c3e5e3ce8"
integrity sha512-QPFGFsbroh2WoTcLCh3f6peMRfSettYJKCXMS9FNbFav7GWKD2whqACiNLx+Mi+VkP/I+aerB7kEirk+DQx41A==
react-sparklines@^1.7.0: react-sparklines@^1.7.0:
version "1.7.0" version "1.7.0"
resolved "https://registry.yarnpkg.com/react-sparklines/-/react-sparklines-1.7.0.tgz#9b1d97e8c8610095eeb2ad658d2e1fcf91f91a60" resolved "https://registry.yarnpkg.com/react-sparklines/-/react-sparklines-1.7.0.tgz#9b1d97e8c8610095eeb2ad658d2e1fcf91f91a60"