diff --git a/app/soapbox/components/column.js b/app/soapbox/components/column.js index 02cc08743..a8aec1542 100644 --- a/app/soapbox/components/column.js +++ b/app/soapbox/components/column.js @@ -6,18 +6,20 @@ export default class Column extends React.PureComponent { static propTypes = { className: PropTypes.string, + transparent: PropTypes.bool, children: PropTypes.node, label: PropTypes.string, }; render() { - const { className, label, children } = this.props; + const { className, label, children, transparent, ...rest } = this.props; return (
{children}
diff --git a/app/soapbox/components/material_status.js b/app/soapbox/components/material_status.js new file mode 100644 index 000000000..25fd24e05 --- /dev/null +++ b/app/soapbox/components/material_status.js @@ -0,0 +1,30 @@ +/** + * MaterialStatus: like a Status, but with gaps and rounded corners. + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import StatusContainer from 'soapbox/containers/status_container'; + +export default class MaterialStatus extends React.Component { + + static propTypes = { + hidden: PropTypes.bool, + } + + render() { + // Performance: when hidden, don't render the wrapper divs + if (this.props.hidden) { + return ; + } + + return ( +
+
+ +
+
+ ); + } + +} diff --git a/app/soapbox/components/progress_circle.js b/app/soapbox/components/progress_circle.js index da20515c1..022829b7b 100644 --- a/app/soapbox/components/progress_circle.js +++ b/app/soapbox/components/progress_circle.js @@ -2,7 +2,14 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -class ProgressCircle extends React.PureComponent { +export default class ProgressCircle extends React.PureComponent { + + static propTypes = { + progress: PropTypes.number.isRequired, + radius: PropTypes.number, + stroke: PropTypes.number, + title: PropTypes.string, + }; static defaultProps = { radius: 12, @@ -51,12 +58,3 @@ class ProgressCircle extends React.PureComponent { } } - -ProgressCircle.propTypes = { - progress: PropTypes.number.isRequired, - radius: PropTypes.number, - stroke: PropTypes.number, - title: PropTypes.text, -}; - -export default ProgressCircle; diff --git a/app/soapbox/components/status_list.js b/app/soapbox/components/status_list.js index a4837a6c4..f96ec779f 100644 --- a/app/soapbox/components/status_list.js +++ b/app/soapbox/components/status_list.js @@ -3,7 +3,7 @@ import React from 'react'; import { FormattedMessage, defineMessages } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; -import StatusContainer from '../containers/status_container'; +import MaterialStatus from 'soapbox/components/material_status'; import ImmutablePureComponent from 'react-immutable-pure-component'; import LoadGap from './load_gap'; import ScrollableList from './scrollable_list'; @@ -117,7 +117,7 @@ export default class StatusList extends ImmutablePureComponent { onClick={onLoadMore} /> ) : ( - ( - ({ }); -export default @injectIntl -@connect(makeMapStateToProps, mapDispatchToProps) -class StatusContainer extends React.Component { - - render() { - return ( -
- -
- ); - } - -} +export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status)); diff --git a/app/soapbox/features/account_timeline/index.js b/app/soapbox/features/account_timeline/index.js index 8b17fcb2b..2e49ed9db 100644 --- a/app/soapbox/features/account_timeline/index.js +++ b/app/soapbox/features/account_timeline/index.js @@ -177,7 +177,7 @@ class AccountTimeline extends ImmutablePureComponent { } return ( - +
diff --git a/app/soapbox/features/bookmarks/index.js b/app/soapbox/features/bookmarks/index.js index 1d726adb9..0099871f5 100644 --- a/app/soapbox/features/bookmarks/index.js +++ b/app/soapbox/features/bookmarks/index.js @@ -55,7 +55,7 @@ class Bookmarks extends ImmutablePureComponent { const emptyMessage = ; return ( - + + + + {(features.suggestions && isEmpty && !isLoading && !done) ? ( {Component => } diff --git a/app/soapbox/features/public_timeline/index.js b/app/soapbox/features/public_timeline/index.js index a186fc99c..bf840c24e 100644 --- a/app/soapbox/features/public_timeline/index.js +++ b/app/soapbox/features/public_timeline/index.js @@ -97,7 +97,7 @@ class CommunityTimeline extends React.PureComponent { const { intl, onlyMedia, timelineId, siteTitle, showExplanationBox, explanationBoxExpanded } = this.props; return ( - + {showExplanationBox &&
diff --git a/app/soapbox/features/remote_timeline/index.js b/app/soapbox/features/remote_timeline/index.js index 26045e162..2f6aac0dd 100644 --- a/app/soapbox/features/remote_timeline/index.js +++ b/app/soapbox/features/remote_timeline/index.js @@ -85,7 +85,7 @@ class RemoteTimeline extends React.PureComponent { const { intl, hasUnread, onlyMedia, timelineId, instance, pinned } = this.props; return ( - + {!pinned &&
diff --git a/app/soapbox/features/status/components/thread_status.js b/app/soapbox/features/status/components/thread_status.js new file mode 100644 index 000000000..3df38013a --- /dev/null +++ b/app/soapbox/features/status/components/thread_status.js @@ -0,0 +1,54 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import StatusContainer from 'soapbox/containers/status_container'; +import { OrderedSet as ImmutableOrderedSet } from 'immutable'; +import classNames from 'classnames'; + +const mapStateToProps = (state, { id }) => { + return { + replyToId: state.getIn(['statuses', id, 'in_reply_to_id']), + replyCount: state.getIn(['contexts', 'replies', id], ImmutableOrderedSet()).size, + }; +}; + +export default @connect(mapStateToProps) +class ThreadStatus extends React.Component { + + static propTypes = { + focusedStatusId: PropTypes.string, + replyToId: PropTypes.string, + replyCount: PropTypes.number, + } + + renderConnector() { + const { focusedStatusId, replyToId, replyCount } = this.props; + + const isConnectedTop = replyToId && replyToId !== focusedStatusId; + const isConnectedBottom = replyCount > 0; + const isConnected = isConnectedTop || isConnectedBottom; + + if (!isConnected) { + return null; + } + + return ( +
+ ); + } + + render() { + return ( +
+ {this.renderConnector()} + +
+ ); + } + +} diff --git a/app/soapbox/features/status/index.js b/app/soapbox/features/status/index.js index af17aa7ed..7c8e2f999 100644 --- a/app/soapbox/features/status/index.js +++ b/app/soapbox/features/status/index.js @@ -37,7 +37,6 @@ import { initMuteModal } from '../../actions/mutes'; import { initReport } from '../../actions/reports'; import { makeGetStatus } from '../../selectors'; // import ColumnHeader from '../../components/column_header'; -import StatusContainer from '../../containers/status_container'; import { openModal } from '../../actions/modal'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -49,6 +48,7 @@ import { textForScreenReader, defaultMediaVisibility } from '../../components/st import { getSettings } from 'soapbox/actions/settings'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; import { deactivateUserModal, deleteUserModal, deleteStatusModal, toggleStatusSensitivityModal } from 'soapbox/actions/moderation'; +import ThreadStatus from './components/thread_status'; import SubNavigation from 'soapbox/components/sub_navigation'; const messages = defineMessages({ @@ -471,10 +471,13 @@ class Status extends ImmutablePureComponent { } renderStatus(id) { + const { status } = this.props; + return ( - */} -
+
{ancestors && ( -
{ancestors}
+
{ancestors}
)} - -
- +
+ +
+ - -
-
+ +
+ +
{descendants && ( -
{descendants}
+
{descendants}
)}
diff --git a/app/soapbox/features/ui/components/action_button.js b/app/soapbox/features/ui/components/action_button.js index 7161b2e7a..1fb3c6420 100644 --- a/app/soapbox/features/ui/components/action_button.js +++ b/app/soapbox/features/ui/components/action_button.js @@ -104,7 +104,7 @@ class ActionButton extends ImmutablePureComponent { // Follow & Unfollow return (
+ ); } diff --git a/app/soapbox/features/ui/components/column.js b/app/soapbox/features/ui/components/column.js index 4d4986cdc..19ad84a02 100644 --- a/app/soapbox/features/ui/components/column.js +++ b/app/soapbox/features/ui/components/column.js @@ -1,8 +1,9 @@ import React from 'react'; import ColumnHeader from './column_header'; import PropTypes from 'prop-types'; +import Column from 'soapbox/components/column'; -export default class Column extends React.PureComponent { +export default class UIColumn extends React.PureComponent { static propTypes = { heading: PropTypes.string, @@ -17,14 +18,14 @@ export default class Column extends React.PureComponent { } render() { - const { heading, icon, children, active, showBackBtn } = this.props; + const { heading, icon, children, active, showBackBtn, ...rest } = this.props; const columnHeaderId = heading && heading.replace(/ /g, '-'); return ( -
+ {heading && } {children} -
+ ); } diff --git a/app/soapbox/features/ui/components/columns_area.js b/app/soapbox/features/ui/components/columns_area.js index cc35321b2..57f1cd75f 100644 --- a/app/soapbox/features/ui/components/columns_area.js +++ b/app/soapbox/features/ui/components/columns_area.js @@ -30,7 +30,7 @@ class ColumnsArea extends ImmutablePureComponent {
-
+
{children}
diff --git a/app/soapbox/pages/admin_page.js b/app/soapbox/pages/admin_page.js index a91d87461..09fa0d81a 100644 --- a/app/soapbox/pages/admin_page.js +++ b/app/soapbox/pages/admin_page.js @@ -27,7 +27,7 @@ class AdminPage extends ImmutablePureComponent {
-
+
{children}
diff --git a/app/soapbox/pages/default_page.js b/app/soapbox/pages/default_page.js index 04cf5e439..9e5c7a2ab 100644 --- a/app/soapbox/pages/default_page.js +++ b/app/soapbox/pages/default_page.js @@ -45,7 +45,7 @@ class DefaultPage extends ImmutablePureComponent {
-
+
{children}
diff --git a/app/soapbox/pages/empty_page.js b/app/soapbox/pages/empty_page.js index 7ba4da5d5..45a7f24d1 100644 --- a/app/soapbox/pages/empty_page.js +++ b/app/soapbox/pages/empty_page.js @@ -16,7 +16,7 @@ export default class DefaultPage extends ImmutablePureComponent {
-
+
{children}
diff --git a/app/soapbox/pages/group_page.js b/app/soapbox/pages/group_page.js index 9458638b9..d4da40a3f 100644 --- a/app/soapbox/pages/group_page.js +++ b/app/soapbox/pages/group_page.js @@ -54,7 +54,7 @@ class GroupPage extends ImmutablePureComponent {
-
+
{children}
diff --git a/app/soapbox/pages/groups_page.js b/app/soapbox/pages/groups_page.js index e38aaf52e..8d7683cb9 100644 --- a/app/soapbox/pages/groups_page.js +++ b/app/soapbox/pages/groups_page.js @@ -39,7 +39,7 @@ class GroupsPage extends ImmutablePureComponent {
-
+
{children}
diff --git a/app/soapbox/pages/home_page.js b/app/soapbox/pages/home_page.js index da07687e4..882e98939 100644 --- a/app/soapbox/pages/home_page.js +++ b/app/soapbox/pages/home_page.js @@ -67,8 +67,8 @@ class HomePage extends ImmutablePureComponent {
-
-
+
+
{me &&
diff --git a/app/soapbox/pages/profile_page.js b/app/soapbox/pages/profile_page.js index 82657b1a2..8a7e0fdc9 100644 --- a/app/soapbox/pages/profile_page.js +++ b/app/soapbox/pages/profile_page.js @@ -107,8 +107,8 @@ class ProfilePage extends ImmutablePureComponent {
-
-
+
+
{children}
diff --git a/app/soapbox/pages/remote_instance_page.js b/app/soapbox/pages/remote_instance_page.js index 815a21ac7..d5c807a12 100644 --- a/app/soapbox/pages/remote_instance_page.js +++ b/app/soapbox/pages/remote_instance_page.js @@ -48,7 +48,7 @@ class RemoteInstancePage extends ImmutablePureComponent {
-
+
{children}
diff --git a/app/soapbox/pages/status_page.js b/app/soapbox/pages/status_page.js index f3eb5b3ab..db70dcee6 100644 --- a/app/soapbox/pages/status_page.js +++ b/app/soapbox/pages/status_page.js @@ -45,8 +45,8 @@ class StatusPage extends ImmutablePureComponent {
-
-
+
+
{children}
diff --git a/app/styles/accounts.scss b/app/styles/accounts.scss index fe5cfee01..50e87e600 100644 --- a/app/styles/accounts.scss +++ b/app/styles/accounts.scss @@ -463,10 +463,6 @@ a .account__avatar { } .account__section-headline { - background: var(--foreground-color); - width: 100%; - display: flex; - button, a { flex: none; diff --git a/app/styles/chats.scss b/app/styles/chats.scss index bebf3dd7e..b093d7386 100644 --- a/app/styles/chats.scss +++ b/app/styles/chats.scss @@ -366,7 +366,7 @@ max-width: none; } - .columns-area--mobile .column { + .columns-area .column { border-radius: 0; } diff --git a/app/styles/components/buttons.scss b/app/styles/components/buttons.scss index 06e0cb619..f18c3df95 100644 --- a/app/styles/components/buttons.scss +++ b/app/styles/components/buttons.scss @@ -143,7 +143,7 @@ a.button { } } -.follow-button { +.button--follow { display: flex; align-items: center; justify-content: center; diff --git a/app/styles/components/columns.scss b/app/styles/components/columns.scss index 7ff80bd2f..81233865d 100644 --- a/app/styles/components/columns.scss +++ b/app/styles/components/columns.scss @@ -93,7 +93,7 @@ } } -.columns-area--mobile { +.columns-area { display: block; flex-direction: column; width: 100%; @@ -126,6 +126,11 @@ @media (max-width: 580px) { padding: 0; + + .timeline-compose-block { + border-radius: 0; + margin-top: 10px; // Make less claustrophobic + } } @media screen and (min-width: 630px) { @@ -340,31 +345,21 @@ cursor: default; } -.columns-area--mobile .column { +.columns-area .column { @include standard-panel; + &--transparent { + background: transparent; + border-radius: 0; + box-shadow: none; + } + @media screen and (max-width: 580px) { border-radius: 0; - } -} -.columns-area--transparent .column { - background: transparent; - border-radius: 0; - box-shadow: none; - - .column-back-button { - background: transparent; - } - - .account__section-headline { - background: transparent; - border: 0; - } - - .empty-column-indicator, - .error-column { - background: transparent; + .material-status__status { + border-radius: 0; + } } } @@ -817,26 +812,6 @@ } } -.columns-area--transparent .follow-recommendations-container { - @include standard-panel; -} - -// Let transparent columns extend the full width of the screen -@media screen and (max-width: 450px) { - .columns-area__panels__main--transparent { - padding: 0; - } - - .columns-area--transparent { - .status__wrapper, - .detailed-status__wrapper, - .timeline-compose-block, - .follow-recommendations-container { - border-radius: 0; - } - } -} - .column-title { text-align: center; padding: 40px; @@ -896,3 +871,21 @@ border-radius: 0; } } + +// Make MaterialStatus flush against SubNavigation +.sub-navigation ~ .slist .item-list > article:first-child .material-status__status { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +// Display background for loading indicator +.column--transparent { + .slist__append { + @include standard-panel; + } + + .sub-navigation ~ .slist .slist__append { + border-top-left-radius: 0; + border-top-right-radius: 0; + } +} diff --git a/app/styles/components/detailed-status.scss b/app/styles/components/detailed-status.scss index 094dce139..c83c359e7 100644 --- a/app/styles/components/detailed-status.scss +++ b/app/styles/components/detailed-status.scss @@ -111,8 +111,6 @@ } .detailed-status__wrapper { - @include standard-panel; - margin-bottom: 10px; position: relative; overflow: hidden; } @@ -160,9 +158,31 @@ margin-right: 5px; } -/* Connect the first status to the SubNavigation */ -.detailed-status__ancestors .status-container:first-child .status__wrapper, -.detailed-status-container > div:first-child .detailed-status__wrapper { - border-top-left-radius: 0; - border-top-right-radius: 0; +.thread { + &__status { + position: relative; + } + + &__connector { + background: hsla(var(--primary-text-color_hsl), 0.2); + position: absolute; + width: 2px; + left: 33px; + display: none; + + &--bottom { + height: calc(100% - 8px - 48px - 14px); + top: calc(8px + 48px + 13px); + display: block; + } + + @media screen and (min-width: 630px) { + left: 38px; + + &--bottom { + height: calc(100% - 15px - 48px); + top: calc(15px + 48px + 9px); + } + } + } } diff --git a/app/styles/components/media-gallery.scss b/app/styles/components/media-gallery.scss index b39f4f1f6..31d407e3e 100644 --- a/app/styles/components/media-gallery.scss +++ b/app/styles/components/media-gallery.scss @@ -164,7 +164,7 @@ .media-gallery__file-extension__label { display: block; position: absolute; - color: var(--primary-text-color); + color: #fff; background: rgba($base-overlay-background, 0.5); bottom: 6px; left: 6px; diff --git a/app/styles/components/status.scss b/app/styles/components/status.scss index 7fbb7af2f..5c7c08ce0 100644 --- a/app/styles/components/status.scss +++ b/app/styles/components/status.scss @@ -126,15 +126,6 @@ vertical-align: middle; } -.status-container { - padding-bottom: 10px; -} - -.status__wrapper { - @include standard-panel; - padding: 15px 0 10px; -} - .status__wrapper--filtered { color: var(--primary-text-color); border: 0; @@ -179,15 +170,6 @@ margin-top: 8px; } - &.status-direct:not(.read) { - background: var(--brand-color--med); - border-bottom-color: var(--brand-color--med); - - .status__content a { - color: var(--brand-color--hicontrast); - } - } - &.light { .status__relative-time { color: var(--primary-text-color--faint); @@ -719,3 +701,12 @@ a.status-card.compact:hover { } } } + +.material-status { + padding-bottom: 10px; + + &__status { + @include standard-panel; + padding: 15px 0 10px; + } +} diff --git a/app/styles/loading.scss b/app/styles/loading.scss index c7b8c77cb..be819b892 100644 --- a/app/styles/loading.scss +++ b/app/styles/loading.scss @@ -194,6 +194,11 @@ align-items: center; justify-content: center; padding: 20px; + border-radius: 10px; + + @media screen and (max-width: 580px) { + border-radius: 0; + } & > div { width: 100%; diff --git a/app/styles/ui.scss b/app/styles/ui.scss index dbad80cc7..aefadcaaa 100644 --- a/app/styles/ui.scss +++ b/app/styles/ui.scss @@ -447,7 +447,6 @@ &__append { flex: 1 1 auto; position: relative; - min-height: 120px; padding: 30px 15px; } }