From 206e9593ac2c808fe85177ab156027c226da8cb6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 4 Oct 2022 20:13:23 +0200 Subject: [Glitch] Fix logged-out web UI on smaller screens Port e2b561e3a521ff893943c0e9e32952e35934ca54 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/features/ui/util/async-components.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/javascript/flavours/glitch/features/ui/util') diff --git a/app/javascript/flavours/glitch/features/ui/util/async-components.js b/app/javascript/flavours/glitch/features/ui/util/async-components.js index eef3a941d..7ef06ceb7 100644 --- a/app/javascript/flavours/glitch/features/ui/util/async-components.js +++ b/app/javascript/flavours/glitch/features/ui/util/async-components.js @@ -181,3 +181,7 @@ export function FilterModal () { export function Explore () { return import(/* webpackChunkName: "flavours/glitch/async/explore" */'flavours/glitch/features/explore'); } + +export function About () { + return import(/*webpackChunkName: "features/glitch/async/about" */'flavours/glitch/features/about'); +} -- cgit From 07df273f3725bc673b9bc2206796908f58c2500a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 8 Oct 2022 06:01:11 +0200 Subject: [Glitch] Change privacy policy to be rendered in web UI, add REST API Port a2ba01132603174c43c5788a95f9ee127b684c0a to glitch-soc Signed-off-by: Claire --- .../glitch/features/privacy_policy/index.js | 60 ++++++++++++++++ .../glitch/features/ui/components/link_footer.js | 2 +- .../flavours/glitch/features/ui/index.js | 2 + .../glitch/features/ui/util/async-components.js | 4 ++ .../flavours/glitch/styles/components/columns.scss | 3 +- .../flavours/glitch/styles/components/index.scss | 1 + .../glitch/styles/components/privacy_policy.scss | 84 ++++++++++++++++++++++ 7 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/privacy_policy/index.js create mode 100644 app/javascript/flavours/glitch/styles/components/privacy_policy.scss (limited to 'app/javascript/flavours/glitch/features/ui/util') diff --git a/app/javascript/flavours/glitch/features/privacy_policy/index.js b/app/javascript/flavours/glitch/features/privacy_policy/index.js new file mode 100644 index 000000000..816010294 --- /dev/null +++ b/app/javascript/flavours/glitch/features/privacy_policy/index.js @@ -0,0 +1,60 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { title } from 'flavours/glitch/initial_state'; +import { Helmet } from 'react-helmet'; +import { FormattedMessage, FormattedDate, injectIntl, defineMessages } from 'react-intl'; +import Column from 'flavours/glitch/components/column'; +import api from 'flavours/glitch/api'; +import Skeleton from 'flavours/glitch/components/skeleton'; + +const messages = defineMessages({ + title: { id: 'privacy_policy.title', defaultMessage: 'Privacy Policy' }, +}); + +export default @injectIntl +class PrivacyPolicy extends React.PureComponent { + + static propTypes = { + intl: PropTypes.object, + }; + + state = { + content: null, + lastUpdated: null, + isLoading: true, + }; + + componentDidMount () { + api().get('/api/v1/instance/privacy_policy').then(({ data }) => { + this.setState({ content: data.content, lastUpdated: data.updated_at, isLoading: false }); + }).catch(() => { + this.setState({ isLoading: false }); + }); + } + + render () { + const { intl } = this.props; + const { isLoading, content, lastUpdated } = this.state; + + return ( + +
+
+

+

: }} />

+
+ +
+
+ + + {intl.formatMessage(messages.title)} - {title} + + + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/ui/components/link_footer.js b/app/javascript/flavours/glitch/features/ui/components/link_footer.js index cd32c8a3d..8c55a7337 100644 --- a/app/javascript/flavours/glitch/features/ui/components/link_footer.js +++ b/app/javascript/flavours/glitch/features/ui/components/link_footer.js @@ -54,7 +54,7 @@ class LinkFooter extends React.PureComponent { items.push(); items.push(); items.push(); - items.push(); + items.push(); items.push(); if (profileDirectory) { diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 8ea7a0b02..ea99e5097 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -53,6 +53,7 @@ import { Explore, FollowRecommendations, About, + PrivacyPolicy, } from './util/async-components'; import { HotKeys } from 'react-hotkeys'; import { me, title } from 'flavours/glitch/initial_state'; @@ -186,6 +187,7 @@ class SwitchingColumnsArea extends React.PureComponent { + diff --git a/app/javascript/flavours/glitch/features/ui/util/async-components.js b/app/javascript/flavours/glitch/features/ui/util/async-components.js index 7ef06ceb7..5bf8d7fd6 100644 --- a/app/javascript/flavours/glitch/features/ui/util/async-components.js +++ b/app/javascript/flavours/glitch/features/ui/util/async-components.js @@ -185,3 +185,7 @@ export function Explore () { export function About () { return import(/*webpackChunkName: "features/glitch/async/about" */'flavours/glitch/features/about'); } + +export function PrivacyPolicy () { + return import(/*webpackChunkName: "features/glitch/async/privacy_policy" */'flavours/glitch/features/privacy_policy'); +} diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss index b63f2c86f..1827e8c01 100644 --- a/app/javascript/flavours/glitch/styles/components/columns.scss +++ b/app/javascript/flavours/glitch/styles/components/columns.scss @@ -357,7 +357,8 @@ $ui-header-height: 55px; > .scrollable { background: $ui-base-color; - border-radius: 0 0 4px 4px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; } } diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 1c3540b33..a04482a79 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -1778,3 +1778,4 @@ noscript { @import 'announcements'; @import 'explore'; @import 'signed_out'; +@import 'privacy_policy'; diff --git a/app/javascript/flavours/glitch/styles/components/privacy_policy.scss b/app/javascript/flavours/glitch/styles/components/privacy_policy.scss new file mode 100644 index 000000000..f69bf1a07 --- /dev/null +++ b/app/javascript/flavours/glitch/styles/components/privacy_policy.scss @@ -0,0 +1,84 @@ +.privacy-policy { + background: $ui-base-color; + padding: 20px; + + @media screen and (min-width: $no-gap-breakpoint) { + border-radius: 4px; + } + + &__body { + margin-top: 20px; + color: $secondary-text-color; + font-size: 15px; + line-height: 22px; + + h1, + p, + ul, + ol { + margin-bottom: 20px; + } + + ul { + list-style: disc; + } + + ol { + list-style: decimal; + } + + ul, + ol { + padding-left: 1em; + } + + li { + margin-bottom: 10px; + + &::marker { + color: $darker-text-color; + } + + &:last-child { + margin-bottom: 0; + } + } + + h1 { + color: $primary-text-color; + font-size: 19px; + line-height: 24px; + font-weight: 700; + margin-top: 30px; + + &:first-child { + margin-top: 0; + } + } + + strong { + font-weight: 700; + color: $primary-text-color; + } + + em { + font-style: italic; + } + + a { + color: $highlight-text-color; + text-decoration: underline; + + &:focus, + &:hover, + &:active { + text-decoration: none; + } + } + + hr { + border: 1px solid lighten($ui-base-color, 4%); + margin: 30px 0; + } + } +} -- cgit From 9363e5c24e48952ddb9a57a5b7d8cc8fe862fbd5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 20 Oct 2022 14:35:29 +0200 Subject: [Glitch] Change public accounts pages to mount the web UI Port 839f893168ab221b08fa439012189e6c29a2721a to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/components/error_boundary.js | 5 + .../glitch/components/missing_indicator.js | 5 + .../flavours/glitch/containers/mastodon.js | 2 +- .../flavours/glitch/features/about/index.js | 6 +- .../glitch/features/account/components/header.js | 5 +- .../glitch/features/account_timeline/index.js | 12 +- .../glitch/features/bookmarked_statuses/index.js | 1 + .../glitch/features/community_timeline/index.js | 1 + .../flavours/glitch/features/compose/index.js | 5 + .../glitch/features/direct_timeline/index.js | 1 + .../flavours/glitch/features/directory/index.js | 1 + .../glitch/features/domain_blocks/index.js | 6 + .../flavours/glitch/features/explore/index.js | 1 + .../glitch/features/favourited_statuses/index.js | 1 + .../flavours/glitch/features/favourites/index.js | 5 + .../features/follow_recommendations/index.js | 5 + .../glitch/features/follow_requests/index.js | 5 + .../glitch/features/getting_started/index.js | 1 + .../glitch/features/hashtag_timeline/index.js | 1 + .../glitch/features/home_timeline/index.js | 3 +- .../glitch/features/keyboard_shortcuts/index.js | 5 + .../glitch/features/list_timeline/index.js | 1 + .../flavours/glitch/features/lists/index.js | 1 + .../flavours/glitch/features/mutes/index.js | 5 + .../glitch/features/notifications/index.js | 1 + .../glitch/features/pinned_statuses/index.js | 4 + .../glitch/features/privacy_policy/index.js | 6 +- .../glitch/features/public_timeline/index.js | 1 + .../flavours/glitch/features/reblogs/index.js | 5 + .../flavours/glitch/features/status/index.js | 16 +- .../features/ui/components/bundle_column_error.js | 24 +- .../features/ui/components/column_loading.js | 6 +- .../glitch/features/ui/components/columns_area.js | 4 +- .../glitch/features/ui/components/modal_root.js | 21 +- .../flavours/glitch/features/ui/index.js | 4 +- .../glitch/features/ui/util/async-components.js | 8 + .../features/ui/util/react_router_helpers.js | 4 +- app/javascript/flavours/glitch/main.js | 8 - app/javascript/flavours/glitch/packs/public.js | 7 - .../flavours/glitch/reducers/statuses.js | 6 + app/javascript/flavours/glitch/selectors/index.js | 2 +- .../flavours/glitch/styles/containers.scss | 786 --------------------- app/javascript/flavours/glitch/styles/footer.scss | 152 ---- app/javascript/flavours/glitch/styles/index.scss | 1 - .../glitch/styles/mastodon-light/diff.scss | 31 - app/javascript/flavours/glitch/styles/rtl.scss | 74 -- .../flavours/glitch/styles/statuses.scss | 9 +- 47 files changed, 162 insertions(+), 1102 deletions(-) delete mode 100644 app/javascript/flavours/glitch/styles/footer.scss (limited to 'app/javascript/flavours/glitch/features/ui/util') diff --git a/app/javascript/flavours/glitch/components/error_boundary.js b/app/javascript/flavours/glitch/components/error_boundary.js index fd3659de7..e0ca3e2b0 100644 --- a/app/javascript/flavours/glitch/components/error_boundary.js +++ b/app/javascript/flavours/glitch/components/error_boundary.js @@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl'; import { source_url } from 'flavours/glitch/initial_state'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; import StackTrace from 'stacktrace-js'; +import { Helmet } from 'react-helmet'; export default class ErrorBoundary extends React.PureComponent { @@ -122,6 +123,10 @@ export default class ErrorBoundary extends React.PureComponent { )}
+ + + + ); } diff --git a/app/javascript/flavours/glitch/components/missing_indicator.js b/app/javascript/flavours/glitch/components/missing_indicator.js index ee5bf7c1e..08e39c236 100644 --- a/app/javascript/flavours/glitch/components/missing_indicator.js +++ b/app/javascript/flavours/glitch/components/missing_indicator.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import illustration from 'flavours/glitch/images/elephant_ui_disappointed.svg'; import classNames from 'classnames'; +import { Helmet } from 'react-helmet'; const MissingIndicator = ({ fullPage }) => (
@@ -14,6 +15,10 @@ const MissingIndicator = ({ fullPage }) => (
+ + + + ); diff --git a/app/javascript/flavours/glitch/containers/mastodon.js b/app/javascript/flavours/glitch/containers/mastodon.js index eb88c2655..cf870102b 100644 --- a/app/javascript/flavours/glitch/containers/mastodon.js +++ b/app/javascript/flavours/glitch/containers/mastodon.js @@ -83,7 +83,7 @@ export default class Mastodon extends React.PureComponent { - + diff --git a/app/javascript/flavours/glitch/features/about/index.js b/app/javascript/flavours/glitch/features/about/index.js index 8d7f9c108..3d26c59bc 100644 --- a/app/javascript/flavours/glitch/features/about/index.js +++ b/app/javascript/flavours/glitch/features/about/index.js @@ -94,6 +94,7 @@ class About extends React.PureComponent { }), dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, }; componentDidMount () { @@ -108,11 +109,11 @@ class About extends React.PureComponent { } render () { - const { intl, server, extendedDescription, domainBlocks } = this.props; + const { multiColumn, intl, server, extendedDescription, domainBlocks } = this.props; const isLoading = server.get('isLoading'); return ( - +
`${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' /> @@ -212,6 +213,7 @@ class About extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js index 9c7e62fc2..9aca72172 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.js +++ b/app/javascript/flavours/glitch/features/account/components/header.js @@ -273,7 +273,9 @@ class Header extends ImmutablePureComponent { const content = { __html: account.get('note_emojified') }; const displayNameHtml = { __html: account.get('display_name_html') }; const fields = account.get('fields'); - const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct'); + const isLocal = account.get('acct').indexOf('@') === -1; + const acct = isLocal && domain ? `${account.get('acct')}@${domain}` : account.get('acct'); + const isIndexable = !account.get('noindex'); let badge; @@ -353,6 +355,7 @@ class Header extends ImmutablePureComponent { {titleFromAccount(account)} +
); diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js index 68d558e66..222d40ca1 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/index.js +++ b/app/javascript/flavours/glitch/features/account_timeline/index.js @@ -136,19 +136,17 @@ class AccountTimeline extends ImmutablePureComponent { render () { const { accountId, statusIds, featuredStatusIds, isLoading, hasMore, suspended, isAccount, hidden, multiColumn, remote, remoteUrl } = this.props; - if (!isAccount) { + if (isLoading && statusIds.isEmpty()) { return ( - - + ); - } - - if (!statusIds && isLoading) { + } else if (!isLoading && !isAccount) { return ( - + + ); } diff --git a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js index 91dd0e892..8978ac5fc 100644 --- a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js +++ b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.js @@ -99,6 +99,7 @@ class Bookmarks extends ImmutablePureComponent { {intl.formatMessage(messages.heading)} + ); diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js index 77809574d..67bf54875 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.js +++ b/app/javascript/flavours/glitch/features/community_timeline/index.js @@ -155,6 +155,7 @@ class CommunityTimeline extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/compose/index.js b/app/javascript/flavours/glitch/features/compose/index.js index 150e78c48..63cff836c 100644 --- a/app/javascript/flavours/glitch/features/compose/index.js +++ b/app/javascript/flavours/glitch/features/compose/index.js @@ -15,6 +15,7 @@ import { me, mascot } from 'flavours/glitch/initial_state'; import { cycleElefriendCompose } from 'flavours/glitch/actions/compose'; import HeaderContainer from './containers/header_container'; import Column from 'flavours/glitch/components/column'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new post' }, @@ -114,6 +115,10 @@ class Compose extends React.PureComponent { + + + + ); } diff --git a/app/javascript/flavours/glitch/features/direct_timeline/index.js b/app/javascript/flavours/glitch/features/direct_timeline/index.js index cb209ed76..d55c63c2b 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/index.js +++ b/app/javascript/flavours/glitch/features/direct_timeline/index.js @@ -147,6 +147,7 @@ class DirectTimeline extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/directory/index.js b/app/javascript/flavours/glitch/features/directory/index.js index 672a11430..94bcd578c 100644 --- a/app/javascript/flavours/glitch/features/directory/index.js +++ b/app/javascript/flavours/glitch/features/directory/index.js @@ -169,6 +169,7 @@ class Directory extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/domain_blocks/index.js b/app/javascript/flavours/glitch/features/domain_blocks/index.js index acce87d5a..cb0b55c63 100644 --- a/app/javascript/flavours/glitch/features/domain_blocks/index.js +++ b/app/javascript/flavours/glitch/features/domain_blocks/index.js @@ -11,6 +11,7 @@ import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_bloc import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' }, @@ -59,6 +60,7 @@ class Blocks extends ImmutablePureComponent { return ( + , )} + + + + ); } diff --git a/app/javascript/flavours/glitch/features/explore/index.js b/app/javascript/flavours/glitch/features/explore/index.js index 934e309f8..24fa26eec 100644 --- a/app/javascript/flavours/glitch/features/explore/index.js +++ b/app/javascript/flavours/glitch/features/explore/index.js @@ -85,6 +85,7 @@ class Explore extends React.PureComponent { {intl.formatMessage(messages.title)} + )} diff --git a/app/javascript/flavours/glitch/features/favourited_statuses/index.js b/app/javascript/flavours/glitch/features/favourited_statuses/index.js index ae94f05ca..a03e1a4eb 100644 --- a/app/javascript/flavours/glitch/features/favourited_statuses/index.js +++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.js @@ -99,6 +99,7 @@ class Favourites extends ImmutablePureComponent { {intl.formatMessage(messages.heading)} + ); diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js index faaf62dee..47c3279c4 100644 --- a/app/javascript/flavours/glitch/features/favourites/index.js +++ b/app/javascript/flavours/glitch/features/favourites/index.js @@ -11,6 +11,7 @@ import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import AccountContainer from 'flavours/glitch/containers/account_container'; import Column from 'flavours/glitch/features/ui/components/column'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.favourited_by', defaultMessage: 'Favourited by' }, @@ -91,6 +92,10 @@ class Favourites extends ImmutablePureComponent { , )} + + + + ); } diff --git a/app/javascript/flavours/glitch/features/follow_recommendations/index.js b/app/javascript/flavours/glitch/features/follow_recommendations/index.js index f934aeb35..d9d962b7c 100644 --- a/app/javascript/flavours/glitch/features/follow_recommendations/index.js +++ b/app/javascript/flavours/glitch/features/follow_recommendations/index.js @@ -12,6 +12,7 @@ import Column from 'flavours/glitch/features/ui/components/column'; import Account from './components/account'; import imageGreeting from 'mastodon/../images/elephant_ui_greeting.svg'; import Button from 'flavours/glitch/components/button'; +import { Helmet } from 'react-helmet'; const mapStateToProps = state => ({ suggestions: state.getIn(['suggestions', 'items']), @@ -104,6 +105,10 @@ class FollowRecommendations extends ImmutablePureComponent { )}
+ + + +
); } diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js index 47ca1e1bf..7b35e3ec9 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/index.js +++ b/app/javascript/flavours/glitch/features/follow_requests/index.js @@ -12,6 +12,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; import { me } from 'flavours/glitch/initial_state'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' }, @@ -88,6 +89,10 @@ class FollowRequests extends ImmutablePureComponent { , )} + + + +
); } diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js index 39e00e4af..b00383877 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.js +++ b/app/javascript/flavours/glitch/features/getting_started/index.js @@ -194,6 +194,7 @@ const NAVIGATION_PANEL_BREAKPOINT = 600 + (285 * 2) + (10 * 2); {intl.formatMessage(messages.menu)} +
); diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index 80b4c82be..f1827789f 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -228,6 +228,7 @@ class HashtagTimeline extends React.PureComponent { #{id} + ); diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js index aa319b576..23d0440a9 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/index.js +++ b/app/javascript/flavours/glitch/features/home_timeline/index.js @@ -20,7 +20,7 @@ const messages = defineMessages({ title: { id: 'column.home', defaultMessage: 'Home' }, show_announcements: { id: 'home.show_announcements', defaultMessage: 'Show announcements' }, hide_announcements: { id: 'home.hide_announcements', defaultMessage: 'Hide announcements' }, -}); +}); const mapStateToProps = state => ({ hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0, @@ -170,6 +170,7 @@ class HomeTimeline extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js index 06df2ed99..2bc0116d4 100644 --- a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js +++ b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.js @@ -5,6 +5,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ColumnHeader from 'flavours/glitch/components/column_header'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'keyboard_shortcuts.heading', defaultMessage: 'Keyboard Shortcuts' }, @@ -137,6 +138,10 @@ class KeyboardShortcuts extends ImmutablePureComponent { + + + + ); } diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js index 9cc5bc1c4..a94c05c56 100644 --- a/app/javascript/flavours/glitch/features/list_timeline/index.js +++ b/app/javascript/flavours/glitch/features/list_timeline/index.js @@ -215,6 +215,7 @@ class ListTimeline extends React.PureComponent { {title} + ); diff --git a/app/javascript/flavours/glitch/features/lists/index.js b/app/javascript/flavours/glitch/features/lists/index.js index 32217cf41..8773be5e6 100644 --- a/app/javascript/flavours/glitch/features/lists/index.js +++ b/app/javascript/flavours/glitch/features/lists/index.js @@ -80,6 +80,7 @@ class Lists extends ImmutablePureComponent { {intl.formatMessage(messages.heading)} + ); diff --git a/app/javascript/flavours/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js index 764cbef1a..8da106e47 100644 --- a/app/javascript/flavours/glitch/features/mutes/index.js +++ b/app/javascript/flavours/glitch/features/mutes/index.js @@ -11,6 +11,7 @@ import AccountContainer from 'flavours/glitch/containers/account_container'; import { fetchMutes, expandMutes } from 'flavours/glitch/actions/mutes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.mutes', defaultMessage: 'Muted users' }, @@ -72,6 +73,10 @@ class Mutes extends ImmutablePureComponent { , )} + + + + ); } diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 0b26a3d9e..67b155ced 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -373,6 +373,7 @@ class Notifications extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/pinned_statuses/index.js b/app/javascript/flavours/glitch/features/pinned_statuses/index.js index 518d0294b..eeeab46ab 100644 --- a/app/javascript/flavours/glitch/features/pinned_statuses/index.js +++ b/app/javascript/flavours/glitch/features/pinned_statuses/index.js @@ -8,6 +8,7 @@ import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_ import StatusList from 'flavours/glitch/components/status_list'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.pins', defaultMessage: 'Pinned post' }, @@ -54,6 +55,9 @@ class PinnedStatuses extends ImmutablePureComponent { hasMore={hasMore} bindToDocument={!multiColumn} /> + + + ); } diff --git a/app/javascript/flavours/glitch/features/privacy_policy/index.js b/app/javascript/flavours/glitch/features/privacy_policy/index.js index 47ee80038..4618d9e32 100644 --- a/app/javascript/flavours/glitch/features/privacy_policy/index.js +++ b/app/javascript/flavours/glitch/features/privacy_policy/index.js @@ -15,6 +15,7 @@ class PrivacyPolicy extends React.PureComponent { static propTypes = { intl: PropTypes.object, + multiColumn: PropTypes.bool, }; state = { @@ -32,11 +33,11 @@ class PrivacyPolicy extends React.PureComponent { } render () { - const { intl } = this.props; + const { intl, multiColumn } = this.props; const { isLoading, content, lastUpdated } = this.state; return ( - +

@@ -51,6 +52,7 @@ class PrivacyPolicy extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js index 49015c2fb..a61a47de1 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/index.js +++ b/app/javascript/flavours/glitch/features/public_timeline/index.js @@ -159,6 +159,7 @@ class PublicTimeline extends React.PureComponent { {intl.formatMessage(messages.title)} + ); diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js index ed646c6ed..b097ff9d7 100644 --- a/app/javascript/flavours/glitch/features/reblogs/index.js +++ b/app/javascript/flavours/glitch/features/reblogs/index.js @@ -11,6 +11,7 @@ import ColumnHeader from 'flavours/glitch/components/column_header'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ heading: { id: 'column.reblogged_by', defaultMessage: 'Boosted by' }, @@ -92,6 +93,10 @@ class Reblogs extends ImmutablePureComponent { , )} + + + + ); } diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index f84928d2e..2560faf05 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -135,6 +135,7 @@ const makeMapStateToProps = () => { } return { + isLoading: state.getIn(['statuses', props.params.statusId, 'isLoading']), status, ancestorsIds, descendantsIds, @@ -178,6 +179,7 @@ class Status extends ImmutablePureComponent { params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, status: ImmutablePropTypes.map, + isLoading: PropTypes.bool, settings: ImmutablePropTypes.map.isRequired, ancestorsIds: ImmutablePropTypes.list, descendantsIds: ImmutablePropTypes.list, @@ -589,9 +591,17 @@ class Status extends ImmutablePureComponent { render () { let ancestors, descendants; - const { status, settings, ancestorsIds, descendantsIds, intl, domain, multiColumn, usingPiP } = this.props; + const { isLoading, status, settings, ancestorsIds, descendantsIds, intl, domain, multiColumn, usingPiP } = this.props; const { fullscreen } = this.state; + if (isLoading) { + return ( + + + + ); + } + if (status === null) { return ( @@ -611,6 +621,9 @@ class Status extends ImmutablePureComponent { descendants =
{this.renderChildren(descendantsIds)}
; } + const isLocal = status.getIn(['account', 'acct'], '').indexOf('@') === -1; + const isIndexable = !status.getIn(['account', 'noindex']); + const handlers = { moveUp: this.handleHotkeyMoveUp, moveDown: this.handleHotkeyMoveDown, @@ -685,6 +698,7 @@ class Status extends ImmutablePureComponent { {titleFromStatus(status)} +
); diff --git a/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js index 3e979a250..382481905 100644 --- a/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js +++ b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js @@ -2,10 +2,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; -import Column from './column'; -import ColumnHeader from './column_header'; -import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim'; +import Column from 'flavours/glitch/components/column'; +import ColumnHeader from 'flavours/glitch/components/column_header'; import IconButton from 'flavours/glitch/components/icon_button'; +import { Helmet } from 'react-helmet'; const messages = defineMessages({ title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' }, @@ -18,6 +18,7 @@ class BundleColumnError extends React.Component { static propTypes = { onRetry: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, + multiColumn: PropTypes.bool, } handleRetry = () => { @@ -25,16 +26,25 @@ class BundleColumnError extends React.Component { } render () { - const { intl: { formatMessage } } = this.props; + const { multiColumn, intl: { formatMessage } } = this.props; return ( - - - + + +
{formatMessage(messages.body)}
+ + + +
); } diff --git a/app/javascript/flavours/glitch/features/ui/components/column_loading.js b/app/javascript/flavours/glitch/features/ui/components/column_loading.js index 22c00c915..b07385397 100644 --- a/app/javascript/flavours/glitch/features/ui/components/column_loading.js +++ b/app/javascript/flavours/glitch/features/ui/components/column_loading.js @@ -10,6 +10,7 @@ export default class ColumnLoading extends ImmutablePureComponent { static propTypes = { title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), icon: PropTypes.string, + multiColumn: PropTypes.bool, }; static defaultProps = { @@ -18,10 +19,11 @@ export default class ColumnLoading extends ImmutablePureComponent { }; render() { - let { title, icon } = this.props; + let { title, icon, multiColumn } = this.props; + return ( - +
); diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js index 8037c195d..76e9a3690 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.js +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js @@ -140,11 +140,11 @@ class ColumnsArea extends ImmutablePureComponent { } renderLoading = columnId => () => { - return columnId === 'COMPOSE' ? : ; + return columnId === 'COMPOSE' ? : ; } renderError = (props) => { - return ; + return ; } render () { diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index cedfabe03..8767840d6 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -13,10 +13,8 @@ import FavouriteModal from './favourite_modal'; import AudioModal from './audio_modal'; import DoodleModal from './doodle_modal'; import ConfirmationModal from './confirmation_modal'; -import SubscribedLanguagesModal from 'flavours/glitch/features/subscribed_languages_modal'; import FocalPointModal from './focal_point_modal'; import DeprecatedSettingsModal from './deprecated_settings_modal'; -import InteractionModal from 'flavours/glitch/features/interaction_modal'; import { OnboardingModal, MuteModal, @@ -29,7 +27,10 @@ import { PinnedAccountsEditor, CompareHistoryModal, FilterModal, + InteractionModal, + SubscribedLanguagesModal, } from 'flavours/glitch/features/ui/util/async-components'; +import { Helmet } from 'react-helmet'; const MODAL_COMPONENTS = { 'MEDIA': () => Promise.resolve({ default: MediaModal }), @@ -53,8 +54,8 @@ const MODAL_COMPONENTS = { 'PINNED_ACCOUNTS_EDITOR': PinnedAccountsEditor, 'COMPARE_HISTORY': CompareHistoryModal, 'FILTER': FilterModal, - 'SUBSCRIBED_LANGUAGES': () => Promise.resolve({ default: SubscribedLanguagesModal }), - 'INTERACTION': () => Promise.resolve({ default: InteractionModal }), + 'SUBSCRIBED_LANGUAGES': SubscribedLanguagesModal, + 'INTERACTION': InteractionModal, }; export default class ModalRoot extends React.PureComponent { @@ -119,9 +120,15 @@ export default class ModalRoot extends React.PureComponent { return ( {visible && ( - - {(SpecificComponent) => } - + <> + + {(SpecificComponent) => } + + + + + + )} ); diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index eb5c3e87b..0b6ce2ba5 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -210,8 +210,8 @@ class SwitchingColumnsArea extends React.PureComponent { - - + + diff --git a/app/javascript/flavours/glitch/features/ui/util/async-components.js b/app/javascript/flavours/glitch/features/ui/util/async-components.js index 5bf8d7fd6..e1a0723e1 100644 --- a/app/javascript/flavours/glitch/features/ui/util/async-components.js +++ b/app/javascript/flavours/glitch/features/ui/util/async-components.js @@ -182,6 +182,14 @@ export function Explore () { return import(/* webpackChunkName: "flavours/glitch/async/explore" */'flavours/glitch/features/explore'); } +export function InteractionModal () { + return import(/*webpackChunkName: "flavours/glitch/async/modals/interaction_modal" */'flavours/glitch/features/interaction_modal'); +} + +export function SubscribedLanguagesModal () { + return import(/*webpackChunkName: "flavours/glitch/async/modals/subscribed_languages_modal" */'flavours/glitch/features/subscribed_languages_modal'); +} + export function About () { return import(/*webpackChunkName: "features/glitch/async/about" */'flavours/glitch/features/about'); } diff --git a/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js b/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js index e36c512f3..60a81a581 100644 --- a/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js +++ b/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js @@ -53,7 +53,9 @@ export class WrappedRoute extends React.Component { } renderLoading = () => { - return ; + const { multiColumn } = this.props; + + return ; } renderError = (props) => { diff --git a/app/javascript/flavours/glitch/main.js b/app/javascript/flavours/glitch/main.js index ecb19ef54..f1e10df34 100644 --- a/app/javascript/flavours/glitch/main.js +++ b/app/javascript/flavours/glitch/main.js @@ -12,14 +12,6 @@ const perf = require('flavours/glitch/performance'); function main() { perf.start('main()'); - if (window.history && history.replaceState) { - const { pathname, search, hash } = window.location; - const path = pathname + search + hash; - if (!(/^\/web($|\/)/).test(path)) { - history.replaceState(null, document.title, `/web${path}`); - } - } - return ready(async () => { const mountNode = document.getElementById('mastodon'); const props = JSON.parse(mountNode.getAttribute('data-props')); diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js index ae1899638..629ea32b7 100644 --- a/app/javascript/flavours/glitch/packs/public.js +++ b/app/javascript/flavours/glitch/packs/public.js @@ -12,7 +12,6 @@ function main() { const { messages } = getLocale(); const React = require('react'); const ReactDOM = require('react-dom'); - const Rellax = require('rellax'); const { createBrowserHistory } = require('history'); const scrollToDetailedStatus = () => { @@ -90,12 +89,6 @@ function main() { scrollToDetailedStatus(); } - const parallaxComponents = document.querySelectorAll('.parallax'); - - if (parallaxComponents.length > 0 ) { - new Rellax('.parallax', { speed: -1 }); - } - delegate(document, '#registration_user_password_confirmation,#registration_user_password', 'input', () => { const password = document.getElementById('registration_user_password'); const confirmation = document.getElementById('registration_user_password_confirmation'); diff --git a/app/javascript/flavours/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js index 333e4b45c..b47155c5f 100644 --- a/app/javascript/flavours/glitch/reducers/statuses.js +++ b/app/javascript/flavours/glitch/reducers/statuses.js @@ -13,6 +13,8 @@ import { STATUS_REVEAL, STATUS_HIDE, STATUS_COLLAPSE, + STATUS_FETCH_REQUEST, + STATUS_FETCH_FAIL, } from 'flavours/glitch/actions/statuses'; import { TIMELINE_DELETE, @@ -37,6 +39,10 @@ const initialState = ImmutableMap(); export default function statuses(state = initialState, action) { switch(action.type) { + case STATUS_FETCH_REQUEST: + return state.setIn([action.id, 'isLoading'], true); + case STATUS_FETCH_FAIL: + return state.delete(action.id); case STATUS_IMPORT: return importStatus(state, action.status); case STATUSES_IMPORT: diff --git a/app/javascript/flavours/glitch/selectors/index.js b/app/javascript/flavours/glitch/selectors/index.js index 8e6e40d24..df46b58a8 100644 --- a/app/javascript/flavours/glitch/selectors/index.js +++ b/app/javascript/flavours/glitch/selectors/index.js @@ -42,7 +42,7 @@ export const makeGetStatus = () => { ], (statusBase, statusReblog, accountBase, accountReblog, filters) => { - if (!statusBase) { + if (!statusBase || statusBase.get('isLoading')) { return null; } diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss index 3f8165370..75472646e 100644 --- a/app/javascript/flavours/glitch/styles/containers.scss +++ b/app/javascript/flavours/glitch/styles/containers.scss @@ -106,789 +106,3 @@ margin-left: 10px; } } - -.grid-3 { - display: grid; - grid-gap: 10px; - grid-template-columns: 3fr 1fr; - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-column: 1/3; - grid-row: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 2; - } - - .column-2 { - grid-column: 2; - grid-row: 2; - } - - .column-3 { - grid-column: 1/3; - grid-row: 3; - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - grid-template-columns: minmax(0, 100%); - - .column-0 { - grid-column: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 3; - } - - .column-2 { - grid-column: 1; - grid-row: 2; - } - - .column-3 { - grid-column: 1; - grid-row: 4; - } - } -} - -.grid-4 { - display: grid; - grid-gap: 10px; - grid-template-columns: repeat(4, minmax(0, 1fr)); - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-column: 1 / 5; - grid-row: 1; - } - - .column-1 { - grid-column: 1 / 4; - grid-row: 2; - } - - .column-2 { - grid-column: 4; - grid-row: 2; - } - - .column-3 { - grid-column: 2 / 5; - grid-row: 3; - } - - .column-4 { - grid-column: 1; - grid-row: 3; - } - - .landing-page__call-to-action { - min-height: 100%; - } - - .flash-message { - margin-bottom: 10px; - } - - @media screen and (max-width: 738px) { - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - - .landing-page__call-to-action { - padding: 20px; - display: flex; - align-items: center; - justify-content: center; - } - - .row__information-board { - width: 100%; - justify-content: center; - align-items: center; - } - - .row__mascot { - display: none; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - grid-gap: 0; - grid-template-columns: minmax(0, 100%); - - .column-0 { - grid-column: 1; - } - - .column-1 { - grid-column: 1; - grid-row: 3; - } - - .column-2 { - grid-column: 1; - grid-row: 2; - } - - .column-3 { - grid-column: 1; - grid-row: 5; - } - - .column-4 { - grid-column: 1; - grid-row: 4; - } - } -} - -.public-layout { - @media screen and (max-width: $no-gap-breakpoint) { - padding-top: 48px; - } - - .container { - max-width: 960px; - - @media screen and (max-width: $no-gap-breakpoint) { - padding: 0; - } - } - - .header { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - height: 48px; - margin: 10px 0; - display: flex; - align-items: stretch; - justify-content: center; - flex-wrap: nowrap; - overflow: hidden; - - @media screen and (max-width: $no-gap-breakpoint) { - position: fixed; - width: 100%; - top: 0; - left: 0; - margin: 0; - border-radius: 0; - box-shadow: none; - z-index: 110; - } - - & > div { - flex: 1 1 33.3%; - min-height: 1px; - } - - .nav-left { - display: flex; - align-items: stretch; - justify-content: flex-start; - flex-wrap: nowrap; - } - - .nav-center { - display: flex; - align-items: stretch; - justify-content: center; - flex-wrap: nowrap; - } - - .nav-right { - display: flex; - align-items: stretch; - justify-content: flex-end; - flex-wrap: nowrap; - } - - .brand { - display: block; - padding: 15px; - - .logo { - display: block; - height: 18px; - width: auto; - position: relative; - bottom: -2px; - fill: $primary-text-color; - - @media screen and (max-width: $no-gap-breakpoint) { - height: 20px; - } - } - - &:hover, - &:focus, - &:active { - background: lighten($ui-base-color, 12%); - } - } - - .nav-link { - display: flex; - align-items: center; - padding: 0 1rem; - font-size: 12px; - font-weight: 500; - text-decoration: none; - color: $darker-text-color; - white-space: nowrap; - text-align: center; - - &:hover, - &:focus, - &:active { - text-decoration: underline; - color: $primary-text-color; - } - - @media screen and (max-width: 550px) { - &.optional { - display: none; - } - } - } - - .nav-button { - background: lighten($ui-base-color, 16%); - margin: 8px; - margin-left: 0; - border-radius: 4px; - - &:hover, - &:focus, - &:active { - text-decoration: none; - background: lighten($ui-base-color, 20%); - } - } - } - - $no-columns-breakpoint: 600px; - - .grid { - display: grid; - grid-gap: 10px; - grid-template-columns: minmax(300px, 3fr) minmax(298px, 1fr); - grid-auto-columns: 25%; - grid-auto-rows: max-content; - - .column-0 { - grid-row: 1; - grid-column: 1; - } - - .column-1 { - grid-row: 1; - grid-column: 2; - } - - @media screen and (max-width: $no-columns-breakpoint) { - grid-template-columns: 100%; - grid-gap: 0; - - .column-1 { - display: none; - } - } - } - - .page-header { - @media screen and (max-width: $no-gap-breakpoint) { - border-bottom: 0; - } - } - - .public-account-header { - overflow: hidden; - margin-bottom: 10px; - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - - &.inactive { - opacity: 0.5; - - .public-account-header__image, - .avatar { - filter: grayscale(100%); - } - - .logo-button { - background-color: $secondary-text-color; - } - } - - .logo-button { - padding: 3px 15px; - } - - &__image { - border-radius: 4px 4px 0 0; - overflow: hidden; - height: 300px; - position: relative; - background: darken($ui-base-color, 12%); - - &::after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - box-shadow: inset 0 -1px 1px 1px rgba($base-shadow-color, 0.15); - top: 0; - left: 0; - } - - img { - object-fit: cover; - display: block; - width: 100%; - height: 100%; - margin: 0; - border-radius: 4px 4px 0 0; - } - - @media screen and (max-width: 600px) { - height: 200px; - } - } - - &--no-bar { - margin-bottom: 0; - - .public-account-header__image, - .public-account-header__image img { - border-radius: 4px; - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin-bottom: 0; - box-shadow: none; - - &__image::after { - display: none; - } - - &__image, - &__image img { - border-radius: 0; - } - } - - &__bar { - position: relative; - margin-top: -80px; - display: flex; - justify-content: flex-start; - - &::before { - content: ""; - display: block; - background: lighten($ui-base-color, 4%); - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 60px; - border-radius: 0 0 4px 4px; - z-index: -1; - } - - .avatar { - display: block; - width: 120px; - height: 120px; - @include avatar-size(120px); - padding-left: 20px - 4px; - flex: 0 0 auto; - - img { - display: block; - width: 100%; - height: 100%; - margin: 0; - border-radius: 50%; - border: 4px solid lighten($ui-base-color, 4%); - background: darken($ui-base-color, 8%); - @include avatar-radius(); - } - } - - @media screen and (max-width: 600px) { - margin-top: 0; - background: lighten($ui-base-color, 4%); - border-radius: 0 0 4px 4px; - padding: 5px; - - &::before { - display: none; - } - - .avatar { - width: 48px; - height: 48px; - @include avatar-size(48px); - padding: 7px 0; - padding-left: 10px; - - img { - border: 0; - border-radius: 4px; - @include avatar-radius(); - } - - @media screen and (max-width: 360px) { - display: none; - } - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - - @media screen and (max-width: $no-columns-breakpoint) { - flex-wrap: wrap; - } - } - - &__tabs { - flex: 1 1 auto; - margin-left: 20px; - - &__name { - padding-top: 20px; - padding-bottom: 8px; - - h1 { - font-size: 20px; - line-height: 18px * 1.5; - color: $primary-text-color; - font-weight: 500; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - text-shadow: 1px 1px 1px $base-shadow-color; - - small { - display: block; - font-size: 14px; - color: $primary-text-color; - font-weight: 400; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - - @media screen and (max-width: 600px) { - margin-left: 15px; - display: flex; - justify-content: space-between; - align-items: center; - - &__name { - padding-top: 0; - padding-bottom: 0; - - h1 { - font-size: 16px; - line-height: 24px; - text-shadow: none; - - small { - color: $darker-text-color; - } - } - } - } - - &__tabs { - display: flex; - justify-content: flex-start; - align-items: stretch; - height: 58px; - - .details-counters { - display: flex; - flex-direction: row; - min-width: 300px; - } - - @media screen and (max-width: $no-columns-breakpoint) { - .details-counters { - display: none; - } - } - - .counter { - min-width: 33.3%; - box-sizing: border-box; - flex: 0 0 auto; - color: $darker-text-color; - padding: 10px; - border-right: 1px solid lighten($ui-base-color, 4%); - cursor: default; - text-align: center; - position: relative; - - a { - display: block; - } - - &:last-child { - border-right: 0; - } - - &::after { - display: block; - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - border-bottom: 4px solid $ui-primary-color; - opacity: 0.5; - transition: all 400ms ease; - } - - &.active { - &::after { - border-bottom: 4px solid $highlight-text-color; - opacity: 1; - } - - &.inactive::after { - border-bottom-color: $secondary-text-color; - } - } - - &:hover { - &::after { - opacity: 1; - transition-duration: 100ms; - } - } - - a { - text-decoration: none; - color: inherit; - } - - .counter-label { - font-size: 12px; - display: block; - } - - .counter-number { - font-weight: 500; - font-size: 18px; - margin-bottom: 5px; - color: $primary-text-color; - font-family: $font-display, sans-serif; - } - } - - .spacer { - flex: 1 1 auto; - height: 1px; - } - - &__buttons { - padding: 7px 8px; - } - } - } - - &__extra { - display: none; - margin-top: 4px; - - .public-account-bio { - border-radius: 0; - box-shadow: none; - background: transparent; - margin: 0 -5px; - - .account__header__fields { - border-top: 1px solid lighten($ui-base-color, 12%); - } - - .roles { - display: none; - } - } - - &__links { - margin-top: -15px; - font-size: 14px; - color: $darker-text-color; - - a { - display: inline-block; - color: $darker-text-color; - text-decoration: none; - padding: 15px; - font-weight: 500; - - strong { - font-weight: 700; - color: $primary-text-color; - } - } - } - - @media screen and (max-width: $no-columns-breakpoint) { - display: block; - flex: 100%; - } - } - } - - .account__section-headline { - border-radius: 4px 4px 0 0; - - @media screen and (max-width: $no-gap-breakpoint) { - border-radius: 0; - } - } - - .detailed-status__meta { - margin-top: 25px; - } - - .public-account-bio { - background: lighten($ui-base-color, 8%); - box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); - border-radius: 4px; - overflow: hidden; - margin-bottom: 10px; - - @media screen and (max-width: $no-gap-breakpoint) { - box-shadow: none; - margin-bottom: 0; - border-radius: 0; - } - - .account__header__fields { - margin: 0; - border-top: 0; - - a { - color: $highlight-text-color; - } - - dl:first-child .verified { - border-radius: 0 4px 0 0; - } - - .verified a { - color: $valid-value-color; - } - } - - .account__header__content { - padding: 20px; - padding-bottom: 0; - color: $primary-text-color; - } - - &__extra, - .roles { - padding: 20px; - font-size: 14px; - color: $darker-text-color; - } - - .roles { - padding-bottom: 0; - } - } - - .directory__list { - display: grid; - grid-gap: 10px; - grid-template-columns: minmax(0, 50%) minmax(0, 50%); - - .account-card { - display: flex; - flex-direction: column; - } - - @media screen and (max-width: $no-gap-breakpoint) { - display: block; - - .account-card { - margin-bottom: 10px; - display: block; - } - } - } - - .card-grid { - display: flex; - flex-wrap: wrap; - min-width: 100%; - margin: 0 -5px; - - & > div { - box-sizing: border-box; - flex: 1 0 auto; - width: 300px; - padding: 0 5px; - margin-bottom: 10px; - max-width: 33.333%; - - @media screen and (max-width: 900px) { - max-width: 50%; - } - - @media screen and (max-width: 600px) { - max-width: 100%; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - margin: 0; - border-top: 1px solid lighten($ui-base-color, 8%); - - & > div { - width: 100%; - padding: 0; - margin-bottom: 0; - border-bottom: 1px solid lighten($ui-base-color, 8%); - - &:last-child { - border-bottom: 0; - } - - .card__bar { - background: $ui-base-color; - - &:hover, - &:active, - &:focus { - background: lighten($ui-base-color, 4%); - } - } - } - } - } -} diff --git a/app/javascript/flavours/glitch/styles/footer.scss b/app/javascript/flavours/glitch/styles/footer.scss deleted file mode 100644 index 0c3e42033..000000000 --- a/app/javascript/flavours/glitch/styles/footer.scss +++ /dev/null @@ -1,152 +0,0 @@ -.public-layout { - .footer { - text-align: left; - padding-top: 20px; - padding-bottom: 60px; - font-size: 12px; - color: lighten($ui-base-color, 34%); - - @media screen and (max-width: $no-gap-breakpoint) { - padding-left: 20px; - padding-right: 20px; - } - - .grid { - display: grid; - grid-gap: 10px; - grid-template-columns: 1fr 1fr 2fr 1fr 1fr; - - .column-0 { - grid-column: 1; - grid-row: 1; - min-width: 0; - } - - .column-1 { - grid-column: 2; - grid-row: 1; - min-width: 0; - } - - .column-2 { - grid-column: 3; - grid-row: 1; - min-width: 0; - text-align: center; - - h4 a { - color: lighten($ui-base-color, 34%); - } - } - - .column-3 { - grid-column: 4; - grid-row: 1; - min-width: 0; - } - - .column-4 { - grid-column: 5; - grid-row: 1; - min-width: 0; - } - - @media screen and (max-width: 690px) { - grid-template-columns: 1fr 2fr 1fr; - - .column-0, - .column-1 { - grid-column: 1; - } - - .column-1 { - grid-row: 2; - } - - .column-2 { - grid-column: 2; - } - - .column-3, - .column-4 { - grid-column: 3; - } - - .column-4 { - grid-row: 2; - } - } - - @media screen and (max-width: 600px) { - .column-1 { - display: block; - } - } - - @media screen and (max-width: $no-gap-breakpoint) { - .column-0, - .column-1, - .column-3, - .column-4 { - display: none; - } - - .column-2 h4 { - display: none; - } - } - } - - .legal-xs { - display: none; - text-align: center; - padding-top: 20px; - - @media screen and (max-width: $no-gap-breakpoint) { - display: block; - } - } - - h4 { - text-transform: uppercase; - font-weight: 700; - margin-bottom: 8px; - color: $darker-text-color; - - a { - color: inherit; - text-decoration: none; - } - } - - ul a, - .legal-xs a { - text-decoration: none; - color: lighten($ui-base-color, 34%); - - &:hover, - &:active, - &:focus { - text-decoration: underline; - } - } - - .brand { - .logo { - display: block; - height: 36px; - width: auto; - margin: 0 auto; - color: lighten($ui-base-color, 34%); - } - - &:hover, - &:focus, - &:active { - .logo { - color: lighten($ui-base-color, 38%); - } - } - } - } -} diff --git a/app/javascript/flavours/glitch/styles/index.scss b/app/javascript/flavours/glitch/styles/index.scss index 5c2532758..fbb02c788 100644 --- a/app/javascript/flavours/glitch/styles/index.scss +++ b/app/javascript/flavours/glitch/styles/index.scss @@ -9,7 +9,6 @@ @import 'containers'; @import 'lists'; @import 'modal'; -@import 'footer'; @import 'widgets'; @import 'forms'; @import 'accounts'; diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index 64b86ffc1..d4ac55847 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -354,37 +354,6 @@ } } -.public-layout { - .header, - .public-account-header, - .public-account-bio { - box-shadow: none; - } - - .header { - background: lighten($ui-base-color, 12%); - } - - .public-account-header { - &__image { - background: lighten($ui-base-color, 12%); - - &::after { - box-shadow: none; - } - } - - &__tabs { - &__name { - h1, - h1 small { - color: $white; - } - } - } - } -} - .account__section-headline a.active::after { border-color: transparent transparent $white; } diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss index d0153c9f9..31d1de376 100644 --- a/app/javascript/flavours/glitch/styles/rtl.scss +++ b/app/javascript/flavours/glitch/styles/rtl.scss @@ -30,16 +30,6 @@ body.rtl { right: -26px; } - .landing-page__logo { - margin-right: 0; - margin-left: 20px; - } - - .landing-page .features-list .features-list__row .visual { - margin-left: 0; - margin-right: 15px; - } - .column-link__icon, .column-header__icon { margin-right: 0; @@ -327,44 +317,6 @@ body.rtl { margin-left: 45px; } - .landing-page .header-wrapper .mascot { - right: 60px; - left: auto; - } - - .landing-page__call-to-action .row__information-board { - direction: rtl; - } - - .landing-page .header .hero .floats .float-1 { - left: -120px; - right: auto; - } - - .landing-page .header .hero .floats .float-2 { - left: 210px; - right: auto; - } - - .landing-page .header .hero .floats .float-3 { - left: 110px; - right: auto; - } - - .landing-page .header .links .brand img { - left: 0; - } - - .landing-page .fa-external-link { - padding-right: 5px; - padding-left: 0 !important; - } - - .landing-page .features #mastodon-timeline { - margin-right: 0; - margin-left: 30px; - } - @media screen and (min-width: 631px) { .column, .drawer { @@ -392,32 +344,6 @@ body.rtl { padding-right: 0; } - .public-layout { - .header { - .nav-button { - margin-left: 8px; - margin-right: 0; - } - } - - .public-account-header__tabs { - margin-left: 0; - margin-right: 20px; - } - } - - .landing-page__information { - .account__display-name { - margin-right: 0; - margin-left: 5px; - } - - .account__avatar-wrapper { - margin-left: 12px; - margin-right: 0; - } - } - .card__bar .display-name { margin-left: 0; margin-right: 15px; diff --git a/app/javascript/flavours/glitch/styles/statuses.scss b/app/javascript/flavours/glitch/styles/statuses.scss index c302fc0d0..947a5d3ae 100644 --- a/app/javascript/flavours/glitch/styles/statuses.scss +++ b/app/javascript/flavours/glitch/styles/statuses.scss @@ -133,8 +133,7 @@ a.button.logo-button { justify-content: center; } -.embed, -.public-layout { +.embed { .status__content[data-spoiler=folded] { .e-content { display: none; @@ -204,8 +203,7 @@ a.button.logo-button { } // Styling from upstream's WebUI, as public pages use the same layout -.embed, -.public-layout { +.embed { .status { .status__info { font-size: 15px; @@ -244,8 +242,7 @@ a.button.logo-button { } .rtl { - .embed, - .public-layout { + .embed { .status { padding-left: 10px; padding-right: 68px; -- cgit From 1315c149c0c6159cf7b7091b31accedb714a648f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 22 Oct 2022 23:18:32 +0200 Subject: [Glitch] Add error boundary around routes in web UI Port a43a8237681187f6e56524aa3effcfc998a877de to glitch-soc Co-authored-by: Yamagishi Kazutoshi Signed-off-by: Claire --- .../features/ui/components/bundle_column_error.js | 160 +++++++++++++++++---- .../flavours/glitch/features/ui/index.js | 6 +- .../features/ui/util/react_router_helpers.js | 34 ++++- .../flavours/glitch/styles/components/columns.scss | 41 +++++- .../flavours/glitch/styles/components/index.scss | 9 ++ .../glitch/styles/components/single_column.scss | 3 +- 6 files changed, 220 insertions(+), 33 deletions(-) (limited to 'app/javascript/flavours/glitch/features/ui/util') diff --git a/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js index 382481905..7cbe1413d 100644 --- a/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js +++ b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js @@ -1,45 +1,155 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { defineMessages, injectIntl } from 'react-intl'; - +import { injectIntl, FormattedMessage } from 'react-intl'; import Column from 'flavours/glitch/components/column'; -import ColumnHeader from 'flavours/glitch/components/column_header'; -import IconButton from 'flavours/glitch/components/icon_button'; +import Button from 'flavours/glitch/components/button'; import { Helmet } from 'react-helmet'; +import { Link } from 'react-router-dom'; +import classNames from 'classnames'; +import { autoPlayGif } from 'flavours/glitch/initial_state'; + +class GIF extends React.PureComponent { + + static propTypes = { + src: PropTypes.string.isRequired, + staticSrc: PropTypes.string.isRequired, + className: PropTypes.string, + animate: PropTypes.bool, + }; + + static defaultProps = { + animate: autoPlayGif, + }; + + state = { + hovering: false, + }; + + handleMouseEnter = () => { + const { animate } = this.props; + + if (!animate) { + this.setState({ hovering: true }); + } + } + + handleMouseLeave = () => { + const { animate } = this.props; + + if (!animate) { + this.setState({ hovering: false }); + } + } + + render () { + const { src, staticSrc, className, animate } = this.props; + const { hovering } = this.state; + + return ( + + ); + } + +} + +class CopyButton extends React.PureComponent { + + static propTypes = { + children: PropTypes.node.isRequired, + value: PropTypes.string.isRequired, + }; + + state = { + copied: false, + }; + + handleClick = () => { + const { value } = this.props; + navigator.clipboard.writeText(value); + this.setState({ copied: true }); + this.timeout = setTimeout(() => this.setState({ copied: false }), 700); + } + + componentWillUnmount () { + if (this.timeout) clearTimeout(this.timeout); + } + + render () { + const { children } = this.props; + const { copied } = this.state; + + return ( + + ); + } -const messages = defineMessages({ - title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' }, - body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this component.' }, - retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' }, -}); +} -class BundleColumnError extends React.Component { +export default @injectIntl +class BundleColumnError extends React.PureComponent { static propTypes = { - onRetry: PropTypes.func.isRequired, + errorType: PropTypes.oneOf(['routing', 'network', 'error']), + onRetry: PropTypes.func, intl: PropTypes.object.isRequired, multiColumn: PropTypes.bool, - } + stacktrace: PropTypes.string, + }; + + static defaultProps = { + errorType: 'routing', + }; handleRetry = () => { - this.props.onRetry(); + const { onRetry } = this.props; + + if (onRetry) { + onRetry(); + } } render () { - const { multiColumn, intl: { formatMessage } } = this.props; + const { errorType, multiColumn, stacktrace } = this.props; - return ( - - + let title, body; + switch(errorType) { + case 'routing': + title = ; + body = ; + break; + case 'network': + title = ; + body = ; + break; + case 'error': + title = ; + body = ; + break; + } + + return ( +
- - {formatMessage(messages.body)} + + +
+

{title}

+

{body}

+ +
+ {errorType === 'network' && } + {errorType === 'error' && } + +
+
@@ -50,5 +160,3 @@ class BundleColumnError extends React.Component { } } - -export default injectIntl(BundleColumnError); diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 5c567be42..9ca946142 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import LoadingBarContainer from './containers/loading_bar_container'; import ModalContainer from './containers/modal_container'; import { connect } from 'react-redux'; -import { Redirect, withRouter } from 'react-router-dom'; +import { Redirect, Route, withRouter } from 'react-router-dom'; import { layoutFromWindow } from 'flavours/glitch/is_mobile'; import { debounce } from 'lodash'; import { uploadCompose, resetCompose, changeComposeSpoilerness } from 'flavours/glitch/actions/compose'; @@ -15,6 +15,7 @@ import { clearHeight } from 'flavours/glitch/actions/height_cache'; import { changeLayout } from 'flavours/glitch/actions/app'; import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; +import BundleColumnError from './components/bundle_column_error'; import UploadArea from './components/upload_area'; import PermaLink from 'flavours/glitch/components/permalink'; import ColumnsAreaContainer from './containers/columns_area_container'; @@ -39,7 +40,6 @@ import { HashtagTimeline, Notifications, FollowRequests, - GenericNotFound, FavouritedStatuses, BookmarkedStatuses, ListTimeline, @@ -233,7 +233,7 @@ class SwitchingColumnsArea extends React.PureComponent { - + ); diff --git a/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js b/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js index 60a81a581..8946c8252 100644 --- a/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js +++ b/app/javascript/flavours/glitch/features/ui/util/react_router_helpers.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Switch, Route } from 'react-router-dom'; - +import StackTrace from 'stacktrace-js'; import ColumnLoading from 'flavours/glitch/features/ui/components/column_loading'; import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error'; import BundleContainer from 'flavours/glitch/features/ui/containers/bundle_container'; @@ -42,8 +42,38 @@ export class WrappedRoute extends React.Component { componentParams: {}, }; + static getDerivedStateFromError () { + return { + hasError: true, + }; + }; + + state = { + hasError: false, + stacktrace: '', + }; + + componentDidCatch (error) { + StackTrace.fromError(error).then(stackframes => { + this.setState({ stacktrace: error.toString() + '\n' + stackframes.map(frame => frame.toString()).join('\n') }); + }).catch(err => { + console.error(err); + }); + } + renderComponent = ({ match }) => { const { component, content, multiColumn, componentParams } = this.props; + const { hasError, stacktrace } = this.state; + + if (hasError) { + return ( + + ); + } return ( @@ -59,7 +89,7 @@ export class WrappedRoute extends React.Component { } renderError = (props) => { - return ; + return ; } render () { diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss index 75891ad2e..5de8547e9 100644 --- a/app/javascript/flavours/glitch/styles/components/columns.scss +++ b/app/javascript/flavours/glitch/styles/components/columns.scss @@ -627,7 +627,6 @@ $ui-header-height: 55px; } .empty-column-indicator, -.error-column, .follow_requests-unlocked_explanation { color: $dark-text-color; background: $ui-base-color; @@ -664,7 +663,47 @@ $ui-header-height: 55px; } .error-column { + padding: 20px; + background: $ui-base-color; + border-radius: 4px; + display: flex; + flex: 1 1 auto; + align-items: center; + justify-content: center; flex-direction: column; + cursor: default; + + &__image { + max-width: 350px; + margin-top: -50px; + } + + &__message { + text-align: center; + color: $darker-text-color; + font-size: 15px; + line-height: 22px; + + h1 { + font-size: 28px; + line-height: 33px; + font-weight: 700; + margin-bottom: 15px; + color: $primary-text-color; + } + + p { + max-width: 48ch; + } + + &__actions { + margin-top: 30px; + display: flex; + gap: 10px; + align-items: center; + justify-content: center; + } + } } // more fixes for the navbar-under mode diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss index 81d90f442..8877626b8 100644 --- a/app/javascript/flavours/glitch/styles/components/index.scss +++ b/app/javascript/flavours/glitch/styles/components/index.scss @@ -189,6 +189,15 @@ color: $highlight-text-color; } + &.copyable { + transition: background 300ms linear; + } + + &.copied { + background: $valid-value-color; + transition: none; + } + &::-moz-focus-inner { border: 0; } diff --git a/app/javascript/flavours/glitch/styles/components/single_column.scss b/app/javascript/flavours/glitch/styles/components/single_column.scss index 3befca567..1725a5480 100644 --- a/app/javascript/flavours/glitch/styles/components/single_column.scss +++ b/app/javascript/flavours/glitch/styles/components/single_column.scss @@ -322,7 +322,8 @@ .column-header, .column-back-button, - .scrollable { + .scrollable, + .error-column { border-radius: 0 !important; } } -- cgit From 05c1dd9114c605a535a405d5a232e17a07007c45 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 26 Oct 2022 19:35:55 +0200 Subject: [Glitch] Add closed registrations modal Port 2277913f3f01d3bdb9a1661f019221b1cb185fbb to glitch-soc Signed-off-by: Claire --- .../features/closed_registrations_modal/index.js | 75 ++++++++++++++++++++++ .../glitch/features/interaction_modal/index.js | 33 +++++++++- .../glitch/features/ui/components/modal_root.js | 2 + .../features/ui/components/sign_in_banner.js | 43 ++++++++++--- .../glitch/features/ui/util/async-components.js | 4 ++ 5 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/closed_registrations_modal/index.js (limited to 'app/javascript/flavours/glitch/features/ui/util') diff --git a/app/javascript/flavours/glitch/features/closed_registrations_modal/index.js b/app/javascript/flavours/glitch/features/closed_registrations_modal/index.js new file mode 100644 index 000000000..25dc4e20f --- /dev/null +++ b/app/javascript/flavours/glitch/features/closed_registrations_modal/index.js @@ -0,0 +1,75 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { FormattedMessage } from 'react-intl'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { domain } from 'flavours/glitch/initial_state'; +import { fetchServer } from 'flavours/glitch/actions/server'; + +const mapStateToProps = state => ({ + closed_registrations_message: state.getIn(['server', 'server', 'registrations', 'closed_registrations_message']), +}); + +export default @connect(mapStateToProps) +class ClosedRegistrationsModal extends ImmutablePureComponent { + + componentDidMount () { + const { dispatch } = this.props; + dispatch(fetchServer()); + } + + render () { + let closedRegistrationsMessage; + + if (this.props.closed_registrations_message) { + closedRegistrationsMessage = ( +

+ ); + } else { + closedRegistrationsMessage = ( +

+ {domain} }} + /> +

+ ); + } + + return ( +
+
+

+

+ +

+
+ +
+
+

+ {closedRegistrationsMessage} +
+ +
+

+

+ +

+ +
+
+
+ ); + } + +}; diff --git a/app/javascript/flavours/glitch/features/interaction_modal/index.js b/app/javascript/flavours/glitch/features/interaction_modal/index.js index 5623f8a06..4cd8e51de 100644 --- a/app/javascript/flavours/glitch/features/interaction_modal/index.js +++ b/app/javascript/flavours/glitch/features/interaction_modal/index.js @@ -5,11 +5,19 @@ import { registrationsOpen } from 'flavours/glitch/initial_state'; import { connect } from 'react-redux'; import Icon from 'flavours/glitch/components/icon'; import classNames from 'classnames'; +import { openModal, closeModal } from 'flavours/glitch/actions/modal'; const mapStateToProps = (state, { accountId }) => ({ displayNameHtml: state.getIn(['accounts', accountId, 'display_name_html']), }); +const mapDispatchToProps = (dispatch) => ({ + onSignupClick() { + dispatch(closeModal()); + dispatch(openModal('CLOSED_REGISTRATIONS')); + }, +}); + class Copypaste extends React.PureComponent { static propTypes = { @@ -66,15 +74,20 @@ class Copypaste extends React.PureComponent { } -export default @connect(mapStateToProps) +export default @connect(mapStateToProps, mapDispatchToProps) class InteractionModal extends React.PureComponent { static propTypes = { displayNameHtml: PropTypes.string, url: PropTypes.string, type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow']), + onSignupClick: PropTypes.func.isRequired, }; + handleSignupClick = () => { + this.props.onSignupClick(); + } + render () { const { url, type, displayNameHtml } = this.props; @@ -105,6 +118,22 @@ class InteractionModal extends React.PureComponent { break; } + let signupButton; + + if (registrationsOpen) { + signupButton = ( + + + + ); + } else { + signupButton = ( + + ); + } + return (
@@ -116,7 +145,7 @@ class InteractionModal extends React.PureComponent {

- + {signupButton}
diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js index 8767840d6..93834f60e 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.js +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js @@ -29,6 +29,7 @@ import { FilterModal, InteractionModal, SubscribedLanguagesModal, + ClosedRegistrationsModal, } from 'flavours/glitch/features/ui/util/async-components'; import { Helmet } from 'react-helmet'; @@ -56,6 +57,7 @@ const MODAL_COMPONENTS = { 'FILTER': FilterModal, 'SUBSCRIBED_LANGUAGES': SubscribedLanguagesModal, 'INTERACTION': InteractionModal, + 'CLOSED_REGISTRATIONS': ClosedRegistrationsModal, }; export default class ModalRoot extends React.PureComponent { diff --git a/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js b/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js index a935d7422..e8023803f 100644 --- a/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js +++ b/app/javascript/flavours/glitch/features/ui/components/sign_in_banner.js @@ -1,13 +1,40 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; +import { useDispatch } from 'react-redux'; import { registrationsOpen } from 'flavours/glitch/initial_state'; +import { openModal } from 'flavours/glitch/actions/modal'; -const SignInBanner = () => ( -
-

- - -
-); +const SignInBanner = () => { + const dispatch = useDispatch(); + + const openClosedRegistrationsModal = useCallback( + () => dispatch(openModal('CLOSED_REGISTRATIONS')), + [dispatch], + ); + + let signupButton; + + if (registrationsOpen) { + signupButton = ( + + + + ); + } else { + signupButton = ( + + ); + } + + return ( +
+

+ + {signupButton} +
+ ); +}; export default SignInBanner; diff --git a/app/javascript/flavours/glitch/features/ui/util/async-components.js b/app/javascript/flavours/glitch/features/ui/util/async-components.js index e1a0723e1..025b22e61 100644 --- a/app/javascript/flavours/glitch/features/ui/util/async-components.js +++ b/app/javascript/flavours/glitch/features/ui/util/async-components.js @@ -190,6 +190,10 @@ export function SubscribedLanguagesModal () { return import(/*webpackChunkName: "flavours/glitch/async/modals/subscribed_languages_modal" */'flavours/glitch/features/subscribed_languages_modal'); } +export function ClosedRegistrationsModal () { + return import(/*webpackChunkName: "flavours/glitch/async/modals/closed_registrations_modal" */'flavours/glitch/features/closed_registrations_modal'); +} + export function About () { return import(/*webpackChunkName: "features/glitch/async/about" */'flavours/glitch/features/about'); } -- cgit