diff --git a/app/javascript/flavours/glitch/components/dismissable_banner.js b/app/javascript/flavours/glitch/components/dismissable_banner.js new file mode 100644 index 000000000..ff52a619d --- /dev/null +++ b/app/javascript/flavours/glitch/components/dismissable_banner.js @@ -0,0 +1,51 @@ +import React from 'react'; +import IconButton from './icon_button'; +import PropTypes from 'prop-types'; +import { injectIntl, defineMessages } from 'react-intl'; +import { bannerSettings } from 'flavours/glitch/settings'; + +const messages = defineMessages({ + dismiss: { id: 'dismissable_banner.dismiss', defaultMessage: 'Dismiss' }, +}); + +export default @injectIntl +class DismissableBanner extends React.PureComponent { + + static propTypes = { + id: PropTypes.string.isRequired, + children: PropTypes.node, + intl: PropTypes.object.isRequired, + }; + + state = { + visible: !bannerSettings.get(this.props.id), + }; + + handleDismiss = () => { + const { id } = this.props; + this.setState({ visible: false }, () => bannerSettings.set(id, true)); + } + + render () { + const { visible } = this.state; + + if (!visible) { + return null; + } + + const { children, intl } = this.props; + + return ( +
+
+ {children} +
+ +
+ +
+
+ ); + } + +} diff --git a/app/javascript/flavours/glitch/features/about/index.js b/app/javascript/flavours/glitch/features/about/index.js index 9f7c90d91..4500480f5 100644 --- a/app/javascript/flavours/glitch/features/about/index.js +++ b/app/javascript/flavours/glitch/features/about/index.js @@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; import Column from 'flavours/glitch/components/column'; import LinkFooter from 'flavours/glitch/features/ui/components/link_footer'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; const messages = defineMessages({ title: { id: 'column.about', defaultMessage: 'About' }, @@ -25,7 +24,7 @@ class About extends React.PureComponent { - {intl.formatMessage(messages.title)} - {title} + {intl.formatMessage(messages.title)} ); diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js index 5ee46ca3b..77809574d 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.js +++ b/app/javascript/flavours/glitch/features/community_timeline/index.js @@ -10,7 +10,8 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col import ColumnSettingsContainer from './containers/column_settings_container'; import { connectCommunityStream } from 'flavours/glitch/actions/streaming'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; +import { domain } from 'flavours/glitch/initial_state'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const messages = defineMessages({ title: { id: 'column.community', defaultMessage: 'Local timeline' }, @@ -138,6 +139,10 @@ class CommunityTimeline extends React.PureComponent { + + + + - {intl.formatMessage(messages.title)} - {title} + {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 dce8fa4e7..672a11430 100644 --- a/app/javascript/flavours/glitch/features/directory/index.js +++ b/app/javascript/flavours/glitch/features/directory/index.js @@ -13,7 +13,6 @@ import RadioButton from 'flavours/glitch/components/radio_button'; import LoadMore from 'flavours/glitch/components/load_more'; import ScrollContainer from 'flavours/glitch/containers/scroll_container'; import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; -import { title } from 'flavours/glitch/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -169,7 +168,7 @@ class Directory extends React.PureComponent { {multiColumn && !pinned ? {scrollableArea} : scrollableArea} - {intl.formatMessage(messages.title)} - {title} + {intl.formatMessage(messages.title)} ); diff --git a/app/javascript/flavours/glitch/features/explore/index.js b/app/javascript/flavours/glitch/features/explore/index.js index f37793732..934e309f8 100644 --- a/app/javascript/flavours/glitch/features/explore/index.js +++ b/app/javascript/flavours/glitch/features/explore/index.js @@ -13,7 +13,6 @@ import Search from 'flavours/glitch/features/compose/containers/search_container import SearchResults from './results'; import { showTrends } from 'flavours/glitch/initial_state'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; const messages = defineMessages({ title: { id: 'explore.title', defaultMessage: 'Explore' }, @@ -85,7 +84,7 @@ class Explore extends React.PureComponent { - {intl.formatMessage(messages.title)} - {title} + {intl.formatMessage(messages.title)} )} diff --git a/app/javascript/flavours/glitch/features/explore/links.js b/app/javascript/flavours/glitch/features/explore/links.js index 6adc2f6fb..092f86b29 100644 --- a/app/javascript/flavours/glitch/features/explore/links.js +++ b/app/javascript/flavours/glitch/features/explore/links.js @@ -6,6 +6,7 @@ import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { connect } from 'react-redux'; import { fetchTrendingLinks } from 'flavours/glitch/actions/trends'; import { FormattedMessage } from 'react-intl'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const mapStateToProps = state => ({ links: state.getIn(['trends', 'links', 'items']), @@ -29,9 +30,17 @@ class Links extends React.PureComponent { render () { const { isLoading, links } = this.props; + const banner = ( + + + + ); + if (!isLoading && links.isEmpty()) { return (
+ {banner} +
@@ -41,6 +50,8 @@ class Links extends React.PureComponent { return (
+ {banner} + {isLoading ? () : links.map(link => ( - {intl.formatMessage(messages.title, { q })} - {title} + {intl.formatMessage(messages.title, { q })} ); diff --git a/app/javascript/flavours/glitch/features/explore/statuses.js b/app/javascript/flavours/glitch/features/explore/statuses.js index fe08ce466..0a5c9de23 100644 --- a/app/javascript/flavours/glitch/features/explore/statuses.js +++ b/app/javascript/flavours/glitch/features/explore/statuses.js @@ -6,6 +6,7 @@ import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; import { fetchTrendingStatuses, expandTrendingStatuses } from 'flavours/glitch/actions/trends'; import { debounce } from 'lodash'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const mapStateToProps = state => ({ statusIds: state.getIn(['status_lists', 'trending', 'items']), @@ -40,17 +41,23 @@ class Statuses extends React.PureComponent { const emptyMessage = ; return ( - + <> + + + + + + ); } diff --git a/app/javascript/flavours/glitch/features/explore/tags.js b/app/javascript/flavours/glitch/features/explore/tags.js index 465fad0df..938036b64 100644 --- a/app/javascript/flavours/glitch/features/explore/tags.js +++ b/app/javascript/flavours/glitch/features/explore/tags.js @@ -6,6 +6,7 @@ import LoadingIndicator from 'flavours/glitch/components/loading_indicator'; import { connect } from 'react-redux'; import { fetchTrendingHashtags } from 'flavours/glitch/actions/trends'; import { FormattedMessage } from 'react-intl'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const mapStateToProps = state => ({ hashtags: state.getIn(['trends', 'tags', 'items']), @@ -29,9 +30,17 @@ class Tags extends React.PureComponent { render () { const { isLoading, hashtags } = this.props; + const banner = ( + + + + ); + if (!isLoading && hashtags.isEmpty()) { return (
+ {banner} +
@@ -41,6 +50,8 @@ class Tags extends React.PureComponent { return (
+ {banner} + {isLoading ? () : hashtags.map(hashtag => ( ))} diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index 5e098514a..80b4c82be 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -14,7 +14,6 @@ import { isEqual } from 'lodash'; import { fetchHashtag, followHashtag, unfollowHashtag } from 'flavours/glitch/actions/tags'; import Icon from 'flavours/glitch/components/icon'; import classNames from 'classnames'; -import { title } from 'flavours/glitch/initial_state'; import { Helmet } from 'react-helmet'; const messages = defineMessages({ @@ -228,7 +227,7 @@ class HashtagTimeline extends React.PureComponent { /> - {`#${id}`} - {title} + #{id} ); diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js index 86aaa0258..aa319b576 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/index.js +++ b/app/javascript/flavours/glitch/features/home_timeline/index.js @@ -15,13 +15,12 @@ import classNames from 'classnames'; import IconWithBadge from 'flavours/glitch/components/icon_with_badge'; import NotSignedInIndicator from 'flavours/glitch/components/not_signed_in_indicator'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; 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,7 +169,7 @@ class HomeTimeline extends React.PureComponent { ) : } - {intl.formatMessage(messages.title)} - {title} + {intl.formatMessage(messages.title)} ); diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 26eeba168..0b26a3d9e 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -30,7 +30,6 @@ import compareId from 'flavours/glitch/compare_id'; import NotificationsPermissionBanner from './components/notifications_permission_banner'; import NotSignedInIndicator from 'flavours/glitch/components/not_signed_in_indicator'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; import NotificationPurgeButtonsContainer from 'flavours/glitch/containers/notification_purge_buttons_container'; @@ -373,7 +372,7 @@ class Notifications extends React.PureComponent { {scrollContainer} - {intl.formatMessage(messages.title)} - {title} + {intl.formatMessage(messages.title)} ); diff --git a/app/javascript/flavours/glitch/features/privacy_policy/index.js b/app/javascript/flavours/glitch/features/privacy_policy/index.js index 816010294..c1f7c4f1e 100644 --- a/app/javascript/flavours/glitch/features/privacy_policy/index.js +++ b/app/javascript/flavours/glitch/features/privacy_policy/index.js @@ -1,6 +1,5 @@ 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'; @@ -51,7 +50,7 @@ class PrivacyPolicy extends React.PureComponent {
- {intl.formatMessage(messages.title)} - {title} + {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 aa70acf15..49015c2fb 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/index.js +++ b/app/javascript/flavours/glitch/features/public_timeline/index.js @@ -10,7 +10,7 @@ import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/col import ColumnSettingsContainer from './containers/column_settings_container'; import { connectPublicStream } from 'flavours/glitch/actions/streaming'; import { Helmet } from 'react-helmet'; -import { title } from 'flavours/glitch/initial_state'; +import DismissableBanner from 'flavours/glitch/components/dismissable_banner'; const messages = defineMessages({ title: { id: 'column.public', defaultMessage: 'Federated timeline' }, @@ -143,6 +143,10 @@ class PublicTimeline extends React.PureComponent { + + + + - {intl.formatMessage(messages.title)} - {title} + {intl.formatMessage(messages.title)} ); diff --git a/app/javascript/flavours/glitch/settings.js b/app/javascript/flavours/glitch/settings.js index 7643a508e..46cfadfa3 100644 --- a/app/javascript/flavours/glitch/settings.js +++ b/app/javascript/flavours/glitch/settings.js @@ -45,3 +45,4 @@ export default class Settings { export const pushNotificationsSetting = new Settings('mastodon_push_notification_data'); export const tagHistory = new Settings('mastodon_tag_history'); +export const bannerSettings = new Settings('mastodon_banner_settings'); diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss index 1827e8c01..6f878f791 100644 --- a/app/javascript/flavours/glitch/styles/components/columns.scss +++ b/app/javascript/flavours/glitch/styles/components/columns.scss @@ -936,3 +936,28 @@ $ui-header-height: 55px; color: $darker-text-color; } } + +.dismissable-banner { + background: $ui-base-color; + border-bottom: 1px solid lighten($ui-base-color, 8%); + display: flex; + align-items: center; + gap: 30px; + + &__message { + flex: 1 1 auto; + padding: 20px 15px; + cursor: default; + font-size: 14px; + line-height: 18px; + color: $primary-text-color; + } + + &__action { + padding: 15px; + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + } +}