diff --git a/app/soapbox/components/pullable.js b/app/soapbox/components/pullable.js
new file mode 100644
index 000000000..52970dd7d
--- /dev/null
+++ b/app/soapbox/components/pullable.js
@@ -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 (
+
+ {children}
+
+ );
+ }
+
+}
diff --git a/app/soapbox/features/account_timeline/index.js b/app/soapbox/features/account_timeline/index.js
index 4d4d916ea..8700710a7 100644
--- a/app/soapbox/features/account_timeline/index.js
+++ b/app/soapbox/features/account_timeline/index.js
@@ -7,7 +7,7 @@ import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../acti
import Icon from 'soapbox/components/icon';
import StatusList from '../../components/status_list';
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 SubNavigation from 'soapbox/components/sub_navigation';
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
diff --git a/app/soapbox/features/chats/index.js b/app/soapbox/features/chats/index.js
index 73f2630bd..da91543c8 100644
--- a/app/soapbox/features/chats/index.js
+++ b/app/soapbox/features/chats/index.js
@@ -8,6 +8,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ChatList from './components/chat_list';
import AudioToggle from 'soapbox/features/chats/components/audio_toggle';
import AccountSearch from 'soapbox/components/account_search';
+import Pullable from 'soapbox/components/pullable';
const messages = defineMessages({
title: { id: 'column.chats', defaultMessage: 'Chats' },
@@ -54,10 +55,12 @@ class ChatIndex extends React.PureComponent {
onSelected={this.handleSuggestion}
/>
- }
- />
+
+ }
+ />
+
);
}
diff --git a/app/soapbox/features/compose/components/search_results.js b/app/soapbox/features/compose/components/search_results.js
index b219ed944..e316123b1 100644
--- a/app/soapbox/features/compose/components/search_results.js
+++ b/app/soapbox/features/compose/components/search_results.js
@@ -11,6 +11,7 @@ import ScrollableList from 'soapbox/components/scrollable_list';
import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder_account';
import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder_hashtag';
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
+import Pullable from 'soapbox/components/pullable';
export default class SearchResults extends ImmutablePureComponent {
@@ -107,18 +108,20 @@ export default class SearchResults extends ImmutablePureComponent {
{noResultsMessage || (
-
- {searchResults}
-
+
+
+ {searchResults}
+
+
)}
>
);
diff --git a/app/soapbox/features/notifications/index.js b/app/soapbox/features/notifications/index.js
index bea5e82a4..61367bad4 100644
--- a/app/soapbox/features/notifications/index.js
+++ b/app/soapbox/features/notifications/index.js
@@ -21,6 +21,7 @@ import TimelineQueueButtonHeader from '../../components/timeline_queue_button_h
import { getSettings } from 'soapbox/actions/settings';
import PlaceholderNotification from 'soapbox/features/placeholder/components/placeholder_notification';
import SubNavigation from 'soapbox/components/sub_navigation';
+import Pullable from 'soapbox/components/pullable';
const messages = defineMessages({
title: { id: 'column.notifications', defaultMessage: 'Notifications' },
@@ -188,7 +189,9 @@ class Notifications extends React.PureComponent {
count={totalQueuedNotificationsCount}
message={messages.queue}
/>
- {scrollContainer}
+
+ {scrollContainer}
+
);
}
diff --git a/app/soapbox/features/search/index.js b/app/soapbox/features/search/index.js
index 48398b749..cb1148460 100644
--- a/app/soapbox/features/search/index.js
+++ b/app/soapbox/features/search/index.js
@@ -1,6 +1,7 @@
import React from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import PropTypes from 'prop-types';
+import Column from 'soapbox/components/column';
import ColumnHeader from 'soapbox/components/column_header';
import SearchContainer from 'soapbox/features/compose/containers/search_container';
import SearchResultsContainer from 'soapbox/features/compose/containers/search_results_container';
@@ -10,11 +11,11 @@ const messages = defineMessages({
});
const Search = ({ intl }) => (
-
+
-
+
);
Search.propTypes = {
diff --git a/app/soapbox/features/status/index.js b/app/soapbox/features/status/index.js
index 79c5d32d1..1c887da96 100644
--- a/app/soapbox/features/status/index.js
+++ b/app/soapbox/features/status/index.js
@@ -8,7 +8,7 @@ import { fetchStatus } from '../../actions/statuses';
import MissingIndicator from '../../components/missing_indicator';
import DetailedStatus from './components/detailed_status';
import ActionBar from './components/action_bar';
-import Column from '../ui/components/column';
+import Column from 'soapbox/components/column';
import {
favourite,
unfavourite,
@@ -52,6 +52,7 @@ import ThreadStatus from './components/thread_status';
import PendingStatus from 'soapbox/features/ui/components/pending_status';
import SubNavigation from 'soapbox/components/sub_navigation';
import { launchChat } from 'soapbox/actions/chats';
+import Pullable from 'soapbox/components/pullable';
const messages = defineMessages({
title: { id: 'status.title', defaultMessage: 'Post' },
@@ -626,56 +627,58 @@ class Status extends ImmutablePureComponent {
*/}
- {ancestors && (
-
{ancestors}
- )}
+
+ {ancestors && (
+ {ancestors}
+ )}
-
- {descendants && (
- {descendants}
- )}
+ {descendants && (
+ {descendants}
+ )}
+
);
diff --git a/app/soapbox/features/ui/components/column.js b/app/soapbox/features/ui/components/column.js
index 19ad84a02..c4a1be2dc 100644
--- a/app/soapbox/features/ui/components/column.js
+++ b/app/soapbox/features/ui/components/column.js
@@ -2,6 +2,7 @@ import React from 'react';
import ColumnHeader from './column_header';
import PropTypes from 'prop-types';
import Column from 'soapbox/components/column';
+import Pullable from 'soapbox/components/pullable';
export default class UIColumn extends React.PureComponent {
@@ -24,7 +25,9 @@ export default class UIColumn extends React.PureComponent {
return (
{heading && }
- {children}
+
+ {children}
+
);
}
diff --git a/app/soapbox/features/ui/components/column_loading.js b/app/soapbox/features/ui/components/column_loading.js
index 7e710f2e3..7ade977e2 100644
--- a/app/soapbox/features/ui/components/column_loading.js
+++ b/app/soapbox/features/ui/components/column_loading.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Column from './column';
+import Column from 'soapbox/components/column';
import ColumnHeader from '../../../components/column_header';
import ImmutablePureComponent from 'react-immutable-pure-component';
import LoadingIndicator from 'soapbox/components/loading_indicator';
diff --git a/app/soapbox/pages/profile_page.js b/app/soapbox/pages/profile_page.js
index ae09b4c2c..84f6c4f5e 100644
--- a/app/soapbox/pages/profile_page.js
+++ b/app/soapbox/pages/profile_page.js
@@ -100,7 +100,7 @@ class ProfilePage extends ImmutablePureComponent {
-
diff --git a/app/styles/components/admin.scss b/app/styles/components/admin.scss
index 96dc141b5..3f9ed12da 100644
--- a/app/styles/components/admin.scss
+++ b/app/styles/components/admin.scss
@@ -127,7 +127,7 @@
display: block;
width: 100%;
max-width: 600px;
- padding: 20px 20px 0;
+ padding: 10px 0;
box-sizing: border-box;
.columns-area__panels__pane__inner {
diff --git a/app/styles/components/columns.scss b/app/styles/components/columns.scss
index 36b172599..1b82cdcfd 100644
--- a/app/styles/components/columns.scss
+++ b/app/styles/components/columns.scss
@@ -99,6 +99,10 @@
margin: 0 auto;
padding-top: 15px;
+ @media screen and (max-width: 580px) {
+ padding-top: 0;
+ }
+
.column {
width: 100%;
padding: 0;
@@ -124,7 +128,7 @@
@media (max-width: 580px) {
.timeline-compose-block {
border-radius: 0;
- margin-top: -5px;
+ margin-top: 10px;
}
}
@@ -959,3 +963,18 @@
.sub-navigation + .account__section-headline {
background: var(--foreground-color);
}
+
+// Pull to refresh
+.columns-area .column {
+ .ptr,
+ .ptr__children {
+ background: var(--foreground-color);
+ }
+
+ &--transparent {
+ .ptr,
+ .ptr__children {
+ background: transparent;
+ }
+ }
+}
diff --git a/app/styles/components/profile-info-panel.scss b/app/styles/components/profile-info-panel.scss
index 699e40924..99bf66c09 100644
--- a/app/styles/components/profile-info-panel.scss
+++ b/app/styles/components/profile-info-panel.scss
@@ -103,10 +103,6 @@
padding: 10px 0;
margin: 5px 0;
- @media screen and (max-width: 895px) {
- border-bottom: 1px solid var(--brand-color--med);
- }
-
a {
color: var(--highlight-text-color);
}
diff --git a/app/styles/loading.scss b/app/styles/loading.scss
index be819b892..c26ec70fe 100644
--- a/app/styles/loading.scss
+++ b/app/styles/loading.scss
@@ -219,3 +219,13 @@
}
}
}
+
+// Pull to refresh
+.lds-ellipsis div {
+ background: var(--primary-text-color--faint) !important;
+}
+
+.ptr,
+.ptr__children {
+ overflow: visible !important;
+}
diff --git a/app/styles/ui.scss b/app/styles/ui.scss
index 62aba1510..b724475e0 100644
--- a/app/styles/ui.scss
+++ b/app/styles/ui.scss
@@ -765,3 +765,9 @@
background: var(--accent-color);
}
}
+
+.page__top + .page__columns .columns-area {
+ @media screen and (max-width: 580px) {
+ padding-top: 10px;
+ }
+}
diff --git a/package.json b/package.json
index be051d030..5f4529840 100644
--- a/package.json
+++ b/package.json
@@ -132,6 +132,7 @@
"react-redux": "^7.2.5",
"react-router-dom": "^4.3.1",
"react-router-scroll-4": "^1.0.0-beta.1",
+ "react-simple-pull-to-refresh": "^1.3.0",
"react-sparklines": "^1.7.0",
"react-stickynode": "^4.0.0",
"react-swipeable-views": "^0.14.0",
diff --git a/yarn.lock b/yarn.lock
index 06faba1a0..53753d04a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -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"
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:
version "1.7.0"
resolved "https://registry.yarnpkg.com/react-sparklines/-/react-sparklines-1.7.0.tgz#9b1d97e8c8610095eeb2ad658d2e1fcf91f91a60"