-
+
+
)
diff --git a/app/javascript/gabsocial/components/scrollable_list.js b/app/javascript/gabsocial/components/scrollable_list.js
index f930c9d0..61ed4f1b 100644
--- a/app/javascript/gabsocial/components/scrollable_list.js
+++ b/app/javascript/gabsocial/components/scrollable_list.js
@@ -128,6 +128,10 @@ export default class ScrollableList extends PureComponent {
const { innerHeight } = this.window;
const offset = scrollHeight - scrollTop - innerHeight;
+ if (scrollTop < -60 && this.props.onReload) {
+ // reload
+ }
+
if (600 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) {
this.props.onLoadMore();
}
diff --git a/app/javascript/gabsocial/components/status_card.js b/app/javascript/gabsocial/components/status_card.js
index 0e9080fd..b0c6dda7 100644
--- a/app/javascript/gabsocial/components/status_card.js
+++ b/app/javascript/gabsocial/components/status_card.js
@@ -141,21 +141,22 @@ export default class StatusCard extends ImmutablePureComponent {
const horizontal = (card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded
const interactive = card.get('type') !== 'link'
+ const cardTitle = `${card.get('title')}`.trim()
const title = interactive ?
(
- {card.get('title')}
+ {cardTitle}
)
: (
- {card.get('title')}
+ {cardTitle}
)
diff --git a/app/javascript/gabsocial/constants.js b/app/javascript/gabsocial/constants.js
index d4f2b7f1..8a80b033 100644
--- a/app/javascript/gabsocial/constants.js
+++ b/app/javascript/gabsocial/constants.js
@@ -22,6 +22,7 @@ export const POPOVER_CONTENT_WARNING = 'CONTENT_WARNING'
export const POPOVER_DATE_PICKER = 'DATE_PICKER'
export const POPOVER_EMOJI_PICKER = 'EMOJI_PICKER'
export const POPOVER_GROUP_INFO = 'GROUP_INFO'
+export const POPOVER_GROUP_OPTIONS = 'GROUP_OPTIONS'
export const POPOVER_PROFILE_OPTIONS = 'PROFILE_OPTIONS'
export const POPOVER_REPOST_OPTIONS = 'REPOST_OPTIONS'
export const POPOVER_SEARCH = 'SEARCH'
@@ -44,8 +45,8 @@ export const MODAL_EMBED = 'EMBED'
export const MODAL_GIF_PICKER = 'GIF_PICKER'
export const MODAL_GROUP_CREATE = 'GROUP_CREATE'
export const MODAL_GROUP_DELETE = 'GROUP_DELETE'
-export const MODAL_GROUP_EDITOR = 'GROUP_EDITOR'
export const MODAL_GROUP_MEMBERS = 'GROUP_MEMBERS'
+export const MODAL_GROUP_REMOVED_ACCOUNTS = 'GROUP_REMOVED_ACCOUNTS'
export const MODAL_HASHTAG_TIMELINE_SETTINGS = 'HASHTAG_TIMELINE_SETTINGS'
export const MODAL_HOME_TIMELINE_SETTINGS = 'HOME_TIMELINE_SETTINGS'
export const MODAL_HOTKEYS = 'HOTKEYS'
diff --git a/app/javascript/gabsocial/features/account_timeline.js b/app/javascript/gabsocial/features/account_timeline.js
index c4bf13ab..eb9a16df 100644
--- a/app/javascript/gabsocial/features/account_timeline.js
+++ b/app/javascript/gabsocial/features/account_timeline.js
@@ -17,8 +17,6 @@ const mapStateToProps = (state, { account, commentsOnly = false }) => {
const path = commentsOnly ? `${accountId}:comments_only` : accountId
- console.log("commentsOnly, path:", commentsOnly, path)
-
return {
accountId,
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),
diff --git a/app/javascript/gabsocial/features/group_members.js b/app/javascript/gabsocial/features/group_members.js
index bf7f1a20..e7c035a5 100644
--- a/app/javascript/gabsocial/features/group_members.js
+++ b/app/javascript/gabsocial/features/group_members.js
@@ -1,86 +1,101 @@
-import ImmutablePureComponent from 'react-immutable-pure-component';
-import ImmutablePropTypes from 'react-immutable-proptypes';
+import ImmutablePureComponent from 'react-immutable-pure-component'
+import ImmutablePropTypes from 'react-immutable-proptypes'
import debounce from 'lodash.debounce'
import {
fetchMembers,
expandMembers,
updateRole,
createRemovedAccount,
-} from '../actions/groups';
-import { FormattedMessage } from 'react-intl';
-import Account from '../components/account';
-import ScrollableList from '../components/scrollable_list';
+} from '../actions/groups'
+import { FormattedMessage } from 'react-intl'
+import Account from '../components/account'
+import ScrollableList from '../components/scrollable_list'
-const mapStateToProps = (state, { params: { id } }) => ({
- group: state.getIn(['groups', id]),
- relationships: state.getIn(['group_relationships', id]),
- accountIds: state.getIn(['user_lists', 'groups', id, 'items']),
- hasMore: !!state.getIn(['user_lists', 'groups', id, 'next']),
-});
+const mapStateToProps = (state, { groupId }) => ({
+ group: state.getIn(['groups', groupId]),
+ relationships: state.getIn(['group_relationships', groupId]),
+ accountIds: state.getIn(['user_lists', 'groups', groupId, 'items']),
+ hasMore: !!state.getIn(['user_lists', 'groups', groupId, 'next']),
+})
+
+const mapDispatchToProps = (dispatch) => ({
+ onFetchMembers(groupId) {
+ dispatch(fetchMembers(groupId))
+ },
+ onExpandMembers(groupId) {
+ dispatch(expandMembers(groupId))
+ },
+})
export default
-@connect(mapStateToProps)
+@connect(mapStateToProps, mapDispatchToProps)
class GroupMembers extends ImmutablePureComponent {
static propTypes = {
- params: PropTypes.object.isRequired,
- dispatch: PropTypes.func.isRequired,
+ groupId: PropTypes.string.isRequired,
accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool,
- };
+ onExpandMembers: PropTypes.func.isRequired,
+ onFetchMembers: PropTypes.func.isRequired,
+ }
componentWillMount() {
- const { params: { id } } = this.props;
+ const { groupId } = this.props
- this.props.dispatch(fetchMembers(id));
+ this.props.onFetchMembers(groupId)
}
componentWillReceiveProps(nextProps) {
- if (nextProps.params.id !== this.props.params.id) {
- this.props.dispatch(fetchMembers(nextProps.params.id));
+ if (nextProps.groupId !== this.props.groupId) {
+ this.props.onFetchMembers(nextProps.groupId)
}
}
handleLoadMore = debounce(() => {
- this.props.dispatch(expandMembers(this.props.params.id));
- }, 300, { leading: true });
+ this.props.onExpandMembers(this.props.groupId)
+ }, 300, { leading: true })
render() {
- const { accountIds, hasMore, group, relationships, dispatch } = this.props;
-
- if (!group || !accountIds || !relationships) {
- return
- }
+ const {
+ accountIds,
+ hasMore,
+ group,
+ relationships,
+ dispatch,
+ } = this.props
return (
}
>
- {accountIds.map(id => {
- let menu = [];
+ {
+ accountIds && accountIds.map((id) => {
+ let menu = []
- if (relationships.get('admin')) {
- menu = [
- { text: 'Remove from group', action: () => dispatch(createRemovedAccount(group.get('id'), id)) },
- { text: 'Make administrator', action: () => dispatch(updateRole(group.get('id'), id, 'admin')) },
- ]
- }
+ if (relationships.get('admin')) {
+ menu = [
+ { text: 'Remove from group', action: () => dispatch(createRemovedAccount(group.get('id'), id)) },
+ { text: 'Make administrator', action: () => dispatch(updateRole(group.get('id'), id, 'admin')) },
+ ]
+ }
- return (
-
-
true} />
- { /*
- menu.length > 0 &&
- */
- }
-
- );
- })}
+ return (
+
true}
+ />
+ )
+ })
+ }
- );
+ )
}
}
diff --git a/app/javascript/gabsocial/features/group_removed_accounts.js b/app/javascript/gabsocial/features/group_removed_accounts.js
index 30aef3bd..cf3dacb9 100644
--- a/app/javascript/gabsocial/features/group_removed_accounts.js
+++ b/app/javascript/gabsocial/features/group_removed_accounts.js
@@ -1,26 +1,25 @@
-import ImmutablePureComponent from 'react-immutable-pure-component';
-import ImmutablePropTypes from 'react-immutable-proptypes';
+import ImmutablePureComponent from 'react-immutable-pure-component'
+import ImmutablePropTypes from 'react-immutable-proptypes'
import debounce from 'lodash.debounce'
-import ColumnIndicator from '../components/column_indicator';
import {
fetchRemovedAccounts,
expandRemovedAccounts,
removeRemovedAccount,
-} from '../actions/groups';
-import { FormattedMessage } from 'react-intl';
-import Account from '../components/account';
-import ScrollableList from '../components/scrollable_list';
-import { defineMessages, injectIntl } from 'react-intl';
+} from '../actions/groups'
+import { FormattedMessage } from 'react-intl'
+import Account from '../components/account'
+import ScrollableList from '../components/scrollable_list'
+import { defineMessages, injectIntl } from 'react-intl'
const messages = defineMessages({
remove: { id: 'groups.removed_accounts', defaultMessage: 'Allow joining' },
-});
+})
-const mapStateToProps = (state, { params: { id } }) => ({
- group: state.getIn(['groups', id]),
- accountIds: state.getIn(['user_lists', 'groups_removed_accounts', id, 'items']),
- hasMore: !!state.getIn(['user_lists', 'groups_removed_accounts', id, 'next']),
-});
+const mapStateToProps = (state, { groupId }) => ({
+ group: state.getIn(['groups', groupId]),
+ accountIds: state.getIn(['user_lists', 'groups_removed_accounts', groupId, 'items']),
+ hasMore: !!state.getIn(['user_lists', 'groups_removed_accounts', groupId, 'next']),
+})
export default
@connect(mapStateToProps)
@@ -28,49 +27,50 @@ export default
class GroupRemovedAccounts extends ImmutablePureComponent {
static propTypes = {
- params: PropTypes.object.isRequired,
+ groupId: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool,
- };
+ }
componentWillMount() {
- const { params: { id } } = this.props;
+ const { groupId } = this.props
- this.props.dispatch(fetchRemovedAccounts(id));
+ this.props.dispatch(fetchRemovedAccounts(groupId))
}
componentWillReceiveProps(nextProps) {
- if (nextProps.params.id !== this.props.params.id) {
- this.props.dispatch(fetchRemovedAccounts(nextProps.params.id));
+ if (nextProps.groupId !== this.props.groupId) {
+ this.props.dispatch(fetchRemovedAccounts(nextProps.groupId))
}
}
handleLoadMore = debounce(() => {
- this.props.dispatch(expandRemovedAccounts(this.props.params.id));
- }, 300, { leading: true });
+ this.props.dispatch(expandRemovedAccounts(this.props.groupId))
+ }, 300, { leading: true })
render() {
- const { accountIds, hasMore, group, intl } = this.props;
-
- if (!group || !accountIds) {
- return
- }
+ const { accountIds, hasMore, group, intl } = this.props
return (
}
>
- {accountIds.map(id => ( this.props.dispatch(removeRemovedAccount(group.get('id'), id))}
- actionTitle={intl.formatMessage(messages.remove)}
- />))}
+ {
+ accountIds && accountIds.map((id) => (
+ this.props.dispatch(removeRemovedAccount(group.get('id'), id))}
+ actionTitle={intl.formatMessage(messages.remove)}
+ />
+ ))
+ }
)
}
diff --git a/app/javascript/gabsocial/features/list_edit.js b/app/javascript/gabsocial/features/list_edit.js
index 83dabde2..96ea6c3d 100644
--- a/app/javascript/gabsocial/features/list_edit.js
+++ b/app/javascript/gabsocial/features/list_edit.js
@@ -229,7 +229,7 @@ class ListEdit extends ImmutablePureComponent {
key={`remove-from-list-${accountId}`}
id={accountId}
onActionClick={() => this.handleAddOrRemoveFromList(accountId)}
- actionIcon={'subtract'}
+ actionIcon='subtract'
/>
))
}
diff --git a/app/javascript/gabsocial/features/ui/ui.js b/app/javascript/gabsocial/features/ui/ui.js
index 38f5bd44..bb25d4ab 100644
--- a/app/javascript/gabsocial/features/ui/ui.js
+++ b/app/javascript/gabsocial/features/ui/ui.js
@@ -153,8 +153,8 @@ class SwitchingArea extends PureComponent {
-
-
+ { /*
+ */}
@@ -208,11 +208,12 @@ class SwitchingArea extends PureComponent {
+ { /*
-
+ */ }
diff --git a/app/javascript/gabsocial/features/ui/util/async_components.js b/app/javascript/gabsocial/features/ui/util/async_components.js
index f27108bf..7edd4e0f 100644
--- a/app/javascript/gabsocial/features/ui/util/async_components.js
+++ b/app/javascript/gabsocial/features/ui/util/async_components.js
@@ -29,9 +29,10 @@ export function GroupsCollection() { return import(/* webpackChunkName: "feature
export function GroupCreate() { return import(/* webpackChunkName: "features/group_create" */'../../group_create') }
export function GroupCreateModal() { return import(/* webpackChunkName: "components/group_create_modal" */'../../../components/modal/group_create_modal') }
export function GroupDeleteModal() { return import(/* webpackChunkName: "components/group_delete_modal" */'../../../components/modal/group_delete_modal') }
-export function GroupEditorModal() { return import(/* webpackChunkName: "components/group_editor_modal" */'../../../components/modal/group_editor_modal') }
+export function GroupRemovedAccountsModal() { return import(/* webpackChunkName: "components/group_removed_accounts_modal" */'../../../components/modal/group_removed_accounts_modal') }
export function GroupMembersModal() { return import(/* webpackChunkName: "components/group_members_modal" */'../../../components/modal/group_members_modal') }
export function GroupInfoPopover() { return import(/* webpackChunkName: "components/group_info_popover" */'../../../components/popover/group_info_popover') }
+export function GroupOptionsPopover() { return import(/* webpackChunkName: "components/group_options_popover" */'../../../components/popover/group_options_popover') }
export function GroupMembers() { return import(/* webpackChunkName: "features/group_members" */'../../group_members') }
export function GroupRemovedAccounts() { return import(/* webpackChunkName: "features/group_removed_accounts" */'../../group_removed_accounts') }
export function GroupTimeline() { return import(/* webpackChunkName: "features/group_timeline" */'../../group_timeline') }
diff --git a/app/javascript/gabsocial/layouts/default_layout.js b/app/javascript/gabsocial/layouts/default_layout.js
index 72d1b962..555674f0 100644
--- a/app/javascript/gabsocial/layouts/default_layout.js
+++ b/app/javascript/gabsocial/layouts/default_layout.js
@@ -7,6 +7,7 @@ export default class DefaultLayout extends PureComponent {
children: PropTypes.node.isRequired,
layout: PropTypes.object,
showBackBtn: PropTypes.bool,
+ noComposeButton: PropTypes.bool,
tabs: PropTypes.array,
title: PropTypes.string.isRequired,
}
@@ -19,6 +20,7 @@ export default class DefaultLayout extends PureComponent {
showBackBtn,
tabs,
title,
+ noComposeButton,
} = this.props
return (
@@ -28,6 +30,7 @@ export default class DefaultLayout extends PureComponent {
showBackBtn={showBackBtn}
tabs={tabs}
title={title}
+ noComposeButton={noComposeButton}
>
{children}
diff --git a/app/javascript/gabsocial/pages/basic_page.js b/app/javascript/gabsocial/pages/basic_page.js
index bb98dff5..c21d0647 100644
--- a/app/javascript/gabsocial/pages/basic_page.js
+++ b/app/javascript/gabsocial/pages/basic_page.js
@@ -17,6 +17,7 @@ export default class BasicPage extends PureComponent {
return (
diff --git a/app/javascript/gabsocial/pages/search_page.js b/app/javascript/gabsocial/pages/search_page.js
index a540b19b..b1f7a70f 100644
--- a/app/javascript/gabsocial/pages/search_page.js
+++ b/app/javascript/gabsocial/pages/search_page.js
@@ -1,8 +1,11 @@
import { Fragment } from 'react'
import { defineMessages, injectIntl } from 'react-intl'
+import { BREAKPOINT_EXTRA_SMALL } from '../constants'
+import Responsive from '../features/ui/util/responsive_component'
import PageTitle from '../features/ui/util/page_title'
import LinkFooter from '../components/link_footer'
import SearchFilterPanel from '../components/panel/search_filter_panel'
+import Search from '../components/search'
import Layout from '../layouts/layout'
const messages = defineMessages({
@@ -59,6 +62,11 @@ class SearchPage extends PureComponent {
)}
>
+
+
+
+
+
{children}
)
diff --git a/app/javascript/gabsocial/reducers/settings.js b/app/javascript/gabsocial/reducers/settings.js
index 43e6af8d..ef4f6a53 100644
--- a/app/javascript/gabsocial/reducers/settings.js
+++ b/app/javascript/gabsocial/reducers/settings.js
@@ -19,11 +19,8 @@ const initialState = ImmutableMap({
home: ImmutableMap({
shows: ImmutableMap({
- photos: true,
- polls: true,
reply: true,
repost: true,
- videos: true,
}),
}),
diff --git a/app/javascript/styles/global.css b/app/javascript/styles/global.css
index 0b1fdbe2..d740e61f 100644
--- a/app/javascript/styles/global.css
+++ b/app/javascript/styles/global.css
@@ -36,6 +36,12 @@
--text_color_tertiary: #777;
--border_color_secondary: #ececed;
+
+ /* Navigation bar. Only themes. Non-editable */
+ --navigation_background: var(--color_brand);
+ --navigation_blend: var(--color_brand-dark);
+ --navigation_primary: var(--color_white);
+ --navigation_brand: var(--color_white);
}
:root[no-circle] {
@@ -59,6 +65,12 @@
--text_color_tertiary: #656565 !important;
--border_color_secondary: #424141 !important;
+
+ /* Navigation bar. Only themes. Non-editable */
+ --navigation_background: #000 !important;
+ --navigation_blend: var(--text_color_secondary) !important;
+ --navigation_primary: var(--text_color_primary) !important;
+ --navigation_brand: var(--color_brand) !important;
}
:root[theme='black'] {
@@ -74,6 +86,12 @@
--text_color_tertiary: #656565 !important;
--border_color_secondary: #212020 !important;
+
+ /* Navigation bar. Only themes. Non-editable */
+ --navigation_background: #000 !important;
+ --navigation_blend: var(--text_color_secondary) !important;
+ --navigation_primary: var(--text_color_primary) !important;
+ --navigation_brand: var(--color_brand) !important;
}
html,
@@ -386,7 +404,7 @@ body {
/* */
-.topNeg60PX { top: -60px; }
+.topNeg80PX { top: -80px; }
.top0 { top: 0; }
.top80PX { top: 80px; }
.top60PC { top: 60%; }
@@ -850,6 +868,30 @@ body {
padding-bottom: env(safe-area-inset-bottom, 0);
}
+.bgNavigation {
+ background-color: var(--navigation_background);
+}
+
+.bgNavigationBlend {
+ background-color: var(--navigation_blend);
+}
+
+.fillNavigation {
+ fill: var(--navigation_primary);
+}
+
+.fillNavigationBlend {
+ fill: var(--navigation_blend);
+}
+
+.colorNavigation {
+ color: var(--navigation_primary);
+}
+
+.fillNavigationBrand {
+ fill: var(--navigation_brand);
+}
+
/**
* Rich Text Editor
*/