From 13dce126655f856f23d02373fa2e333e74bdc36e Mon Sep 17 00:00:00 2001 From: Paweł Ngei Date: Sun, 16 Dec 2018 05:56:41 +0100 Subject: Add notification quick-filter bar in the frontend app (#9399) * create FilterBar componer and its container, unstyled * introduce basic styling for FilterBar * add selection css * allow FilterBar to display active CSS with js * connect the FilterBar to the Redux state * change getNotifications to use filter * remove temporary comments * add an option to turn the FilterBar off in settings * fix showFilterBar data type to boolean * fix eslint errors * add English and Polish translations * allowed filter bar overflow to accomodate for longer languages * fix mispelled translation key * add unified CSS look * replace text in FilterBar with icons * add tooltips * replace text @ with an icon * introduce simple and advanced filtering view * add ability to toggle the advanced view * add Polish translations * change Advanced View description to be more clear * make each filter flush notifications and load new ones, fixing pagination * simplify getNotifications once frontend filtering is not needed for FilterBar * add a semicolon * Revert "simplify getNotifications once frontend filtering is not needed for FilterBar" This reverts commit 9f4be7857135b0327814bd22a3e8a4e7b546f7cc. * reset filter to 'all' when turning off FilterBar --- app/javascript/styles/mastodon/components.scss | 46 ++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'app/javascript/styles') diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index c880e99a9..1c1b8c506 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1484,6 +1484,52 @@ a.account__display-name { } } +.notification__filter-bar { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + background: $ui-base-color; + + & > button { + position: relative; + flex-grow: 1; + color: $primary-text-color; + padding: 10px 5px 12px; + text-decoration: none; + font-weight: 400; + font-size: 15px; + line-height: 18px; + background: darken($ui-base-color, 4%); + border: 0; + border-bottom: 1px solid lighten($ui-base-color, 8%); + cursor: default; + + &.active { + color: $secondary-text-color; + + &::before, + &::after { + display: block; + content: ""; + position: absolute; + bottom: 0; + left: 50%; + width: 0; + height: 0; + transform: translateX(-50%); + border-style: solid; + border-width: 0 10px 10px; + border-color: transparent transparent lighten($ui-base-color, 8%); + } + + &::after { + bottom: -1px; + border-color: transparent transparent $ui-base-color; + } + } + } +} + .notification__message { margin: 0 10px 0 68px; padding: 8px 0 0; -- cgit From 087e11897137dc1f2811c21c3ccc6cec3ccdedb3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 17 Dec 2018 03:14:28 +0100 Subject: Remove "most popular" tab from profile directory, add responsive design (#9539) * Remove "most popular" tab from profile directory, add responsive design * Remove unused translations --- app/controllers/directories_controller.rb | 12 +------ app/javascript/styles/mastodon/containers.scss | 6 ++++ app/javascript/styles/mastodon/widgets.scss | 43 ++++++++++++++++++-------- app/models/account.rb | 3 +- app/views/directories/index.html.haml | 8 ++--- app/views/layouts/public.html.haml | 6 ++-- config/locales/ar.yml | 1 - config/locales/co.yml | 2 -- config/locales/cs.yml | 2 -- config/locales/el.yml | 2 -- config/locales/en.yml | 2 -- config/locales/eu.yml | 2 -- config/locales/fr.yml | 2 -- config/locales/gl.yml | 2 -- config/locales/ja.yml | 2 -- config/locales/nl.yml | 2 -- config/locales/oc.yml | 2 -- config/locales/pl.yml | 2 -- config/locales/sk.yml | 2 -- config/routes.rb | 2 -- 20 files changed, 43 insertions(+), 62 deletions(-) (limited to 'app/javascript/styles') diff --git a/app/controllers/directories_controller.rb b/app/controllers/directories_controller.rb index b8565af4b..df012657a 100644 --- a/app/controllers/directories_controller.rb +++ b/app/controllers/directories_controller.rb @@ -32,22 +32,12 @@ class DirectoriesController < ApplicationController end def set_accounts - @accounts = Account.searchable.discoverable.page(params[:page]).per(50).tap do |query| + @accounts = Account.discoverable.page(params[:page]).per(30).tap do |query| query.merge!(Account.tagged_with(@tag.id)) if @tag - - if popular_requested? - query.merge!(Account.popular) - else - query.merge!(Account.by_recent_status) - end end end def set_instance_presenter @instance_presenter = InstancePresenter.new end - - def popular_requested? - request.path.ends_with?('/popular') - end end diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss index 44fc1e538..8de53ca98 100644 --- a/app/javascript/styles/mastodon/containers.scss +++ b/app/javascript/styles/mastodon/containers.scss @@ -294,6 +294,12 @@ text-decoration: underline; color: $primary-text-color; } + + @media screen and (max-width: $no-gap-breakpoint) { + &.optional { + display: none; + } + } } .nav-button { diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss index c863e3b4f..87e633c70 100644 --- a/app/javascript/styles/mastodon/widgets.scss +++ b/app/javascript/styles/mastodon/widgets.scss @@ -229,18 +229,6 @@ margin-bottom: 10px; } -.moved-account-widget, -.memoriam-widget, -.box-widget, -.contact-widget, -.landing-page__information.contact-widget { - @media screen and (max-width: $no-gap-breakpoint) { - margin-bottom: 0; - box-shadow: none; - border-radius: 0; - } -} - .page-header { background: lighten($ui-base-color, 8%); box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); @@ -261,11 +249,20 @@ font-size: 15px; color: $darker-text-color; } + + @media screen and (max-width: $no-gap-breakpoint) { + margin-top: 0; + background: lighten($ui-base-color, 4%); + + h1 { + font-size: 24px; + } + } } .directory { background: $ui-base-color; - border-radius: 0 0 4px 4px; + border-radius: 4px; box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); &__tag { @@ -407,4 +404,24 @@ font-size: 14px; } } + + @media screen and (max-width: $no-gap-breakpoint) { + tbody td.optional { + display: none; + } + } +} + +.moved-account-widget, +.memoriam-widget, +.box-widget, +.contact-widget, +.landing-page__information.contact-widget, +.directory, +.page-header { + @media screen and (max-width: $no-gap-breakpoint) { + margin-bottom: 0; + box-shadow: none; + border-radius: 0; + } } diff --git a/app/models/account.rb b/app/models/account.rb index 9767e3767..a47741611 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -91,9 +91,8 @@ class Account < ApplicationRecord scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) } scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } scope :searchable, -> { where(suspended: false).where(moved_to_account_id: nil) } - scope :discoverable, -> { where(silenced: false).where(discoverable: true).joins(:account_stat).where(AccountStat.arel_table[:followers_count].gteq(MIN_FOLLOWERS_DISCOVERY)) } + scope :discoverable, -> { searchable.where(silenced: false).where(discoverable: true).joins(:account_stat).where(AccountStat.arel_table[:followers_count].gteq(MIN_FOLLOWERS_DISCOVERY)).by_recent_status } scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) } - scope :popular, -> { order('account_stats.followers_count desc') } scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc')) } delegate :email, diff --git a/app/views/directories/index.html.haml b/app/views/directories/index.html.haml index f70eb964a..88706def7 100644 --- a/app/views/directories/index.html.haml +++ b/app/views/directories/index.html.haml @@ -16,10 +16,6 @@ .grid .column-0 - .account__section-headline - = active_link_to t('directories.most_recently_active'), @tag ? explore_hashtag_path(@tag) : explore_path - = active_link_to t('directories.most_popular'), @tag ? explore_hashtag_popular_path(@tag) : explore_popular_path - - if @accounts.empty? = nothing_here - else @@ -29,10 +25,10 @@ - @accounts.each do |account| %tr %td= account_link_to account - %td.accounts-table__count + %td.accounts-table__count.optional = number_to_human account.statuses_count, strip_insignificant_zeros: true %small= t('accounts.posts', count: account.statuses_count).downcase - %td.accounts-table__count + %td.accounts-table__count.optional = number_to_human account.followers_count, strip_insignificant_zeros: true %small= t('accounts.followers', count: account.followers_count).downcase %td.accounts-table__count diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index 93ed12f18..caccd5bb6 100644 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -10,9 +10,9 @@ = image_tag asset_pack_path('logo_full.svg'), alt: 'Mastodon' - if Setting.profile_directory - = link_to t('directories.directory'), explore_path, class: 'nav-link' - = link_to t('about.about_this'), about_more_path, class: 'nav-link' - = link_to t('about.apps'), 'https://joinmastodon.org/apps', class: 'nav-link' + = link_to t('directories.directory'), explore_path, class: 'nav-link optional' + = link_to t('about.about_this'), about_more_path, class: 'nav-link optional' + = link_to t('about.apps'), 'https://joinmastodon.org/apps', class: 'nav-link optional' .nav-center .nav-right - if user_signed_in? diff --git a/config/locales/ar.yml b/config/locales/ar.yml index eda99e24c..4de1e4e26 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -541,7 +541,6 @@ ar: warning_title: توافر المحتوى المنشور و المبعثَر directories: explore_mastodon: استكشف %{title} - most_popular: المشهورة errors: '403': ليس لك الصلاحيات الكافية لعرض هذه الصفحة. '404': إنّ الصفحة التي تبحث عنها لا وجود لها أصلا. diff --git a/config/locales/co.yml b/config/locales/co.yml index d2dcef9a4..80d2decd3 100644 --- a/config/locales/co.yml +++ b/config/locales/co.yml @@ -531,8 +531,6 @@ co: directory: Annuariu di i prufili explanation: Scopre utilizatori à partesi di i so centri d'interessu explore_mastodon: Scopre à %{title} - most_popular: I più pupulari - most_recently_active: Attività a più fresca people: one: "%{count} persona" other: "%{count} persone" diff --git a/config/locales/cs.yml b/config/locales/cs.yml index a5a3c0184..1bba55f0f 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -536,8 +536,6 @@ cs: directory: Adresář profilů explanation: Objevujte uživatele podle jejich zájmů explore_mastodon: Prozkoumejte %{title} - most_popular: Nejpopulárnější - most_recently_active: Naposledy aktivní people: few: "%{count} lidé" one: "%{count} člověk" diff --git a/config/locales/el.yml b/config/locales/el.yml index 342cad91c..9d41f353f 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -531,8 +531,6 @@ el: directory: Κατάλογος λογαριασμών explanation: Βρες χρήστες βάσει των ενδιαφερόντων τους explore_mastodon: Εξερεύνησε %{title} - most_popular: Δημοφιλείς - most_recently_active: Πρόσφατα ενεργοί people: one: "%{count} άτομο" other: "%{count} άτομα" diff --git a/config/locales/en.yml b/config/locales/en.yml index 314787acd..c8bfccdf7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -535,8 +535,6 @@ en: directory: Profile directory explanation: Discover users based on their interests explore_mastodon: Explore %{title} - most_popular: Most popular - most_recently_active: Most recently active people: one: "%{count} person" other: "%{count} people" diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 15307c76e..c96438bc3 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -531,8 +531,6 @@ eu: directory: Profilen direktorioa explanation: Deskubritu erabiltzaileak interesen arabera explore_mastodon: Esploratu %{title} - most_popular: Puri-purian - most_recently_active: Azkenaldian aktibo people: one: pertsona %{count} other: "%{count} pertsona" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index de3070e8a..c171d9342 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -531,8 +531,6 @@ fr: directory: Annuaire des profils explanation: Découvrir des utilisateurs en se basant sur leurs centres d'intérêt explore_mastodon: Explorer %{title} - most_popular: Les plus populaires - most_recently_active: Les actifs les plus récents people: one: "%{count} personne" other: "%{count} personne" diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 8f12587d6..5f4e420cb 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -531,8 +531,6 @@ gl: directory: Directorio de perfil explanation: Descubra usuarias según o seu interese explore_mastodon: Explorar %{title} - most_popular: Máis popular - most_recently_active: Máis activa recentemente people: one: "%{count} persoa" other: "%{count} persoas" diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 50e9522bc..9c8d7f5b9 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -530,8 +530,6 @@ ja: directories: directory: ディレクトリ explore_mastodon: "%{title}を探索" - most_popular: 人気順 - most_recently_active: 直近の活動順 people: one: "%{count} 人" other: "%{count} 人" diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 30af6562a..b5229d241 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -531,8 +531,6 @@ nl: directory: Gebruikersgids explanation: Ontdek gebruikers aan de hand van hun interesses explore_mastodon: "%{title} verkennen" - most_popular: Meest populair - most_recently_active: Recentelijk actief people: one: "%{count} gebruikers" other: "%{count} gebruikers" diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 8fe3e350a..9015997fc 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -587,8 +587,6 @@ oc: directory: Annuari de perfils explanation: Trobar d’utilizaires segon lor interèsses explore_mastodon: Explorar %{title} - most_popular: Mai populars - most_recently_active: Mai actius recentament people: one: "%{count} persona" other: "%{count} personas" diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 4a0d65440..79ba6f9fb 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -541,8 +541,6 @@ pl: directory: Katalog profilów explanation: Poznaj profile na podstawie zainteresowań explore_mastodon: Odkrywaj %{title} - most_popular: Napopularniejsi - most_recently_active: Ostatnio aktywni people: few: "%{count} osoby" many: "%{count} osób" diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 5f49a2d0e..bea4ac334 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -536,8 +536,6 @@ sk: directory: Databáza profilov explanation: Pátraj po užívateľoch podľa ich záujmov explore_mastodon: Prebádaj %{title} - most_popular: Najpopulárnejšie - most_recently_active: Naposledy aktívni people: few: "%{count} ľudia" one: "%{count} človek" diff --git a/config/routes.rb b/config/routes.rb index 4a0289465..0aba433e2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -81,9 +81,7 @@ Rails.application.routes.draw do post '/interact/:id', to: 'remote_interaction#create' get '/explore', to: 'directories#index', as: :explore - get '/explore/popular', to: 'directories#index', as: :explore_popular get '/explore/:id', to: 'directories#show', as: :explore_hashtag - get '/explore/:id/popular', to: 'directories#show', as: :explore_hashtag_popular namespace :settings do resource :profile, only: [:show, :update] -- cgit From 9cb26bb56b6b61e4e8577519347ada40a7751cd6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 17 Dec 2018 11:07:17 +0100 Subject: Add new first-time tutorial (#9531) * Prepare to load onboarding as a full page * Update the first-time introduction * Improve responsive design * Replace speech bubble with logo * Increase text size and reword first paragraph --- app/javascript/images/screen_federation.svg | 1 + app/javascript/images/screen_hello.svg | 1 + app/javascript/images/screen_interactions.svg | 1 + app/javascript/mastodon/actions/onboarding.js | 14 +- app/javascript/mastodon/containers/mastodon.js | 51 ++-- .../mastodon/features/introduction/index.js | 196 +++++++++++++ .../mastodon/features/ui/components/modal_root.js | 2 - .../features/ui/components/onboarding_modal.js | 324 --------------------- app/javascript/mastodon/features/ui/index.js | 6 + .../mastodon/features/ui/util/async-components.js | 4 - app/javascript/styles/application.scss | 1 + app/javascript/styles/mastodon/components.scss | 239 --------------- app/javascript/styles/mastodon/introduction.scss | 153 ++++++++++ 13 files changed, 397 insertions(+), 596 deletions(-) create mode 100644 app/javascript/images/screen_federation.svg create mode 100644 app/javascript/images/screen_hello.svg create mode 100644 app/javascript/images/screen_interactions.svg create mode 100644 app/javascript/mastodon/features/introduction/index.js delete mode 100644 app/javascript/mastodon/features/ui/components/onboarding_modal.js create mode 100644 app/javascript/styles/mastodon/introduction.scss (limited to 'app/javascript/styles') diff --git a/app/javascript/images/screen_federation.svg b/app/javascript/images/screen_federation.svg new file mode 100644 index 000000000..7019a7356 --- /dev/null +++ b/app/javascript/images/screen_federation.svg @@ -0,0 +1 @@ + diff --git a/app/javascript/images/screen_hello.svg b/app/javascript/images/screen_hello.svg new file mode 100644 index 000000000..7bcdd0afd --- /dev/null +++ b/app/javascript/images/screen_hello.svg @@ -0,0 +1 @@ + diff --git a/app/javascript/images/screen_interactions.svg b/app/javascript/images/screen_interactions.svg new file mode 100644 index 000000000..41873371a --- /dev/null +++ b/app/javascript/images/screen_interactions.svg @@ -0,0 +1 @@ + diff --git a/app/javascript/mastodon/actions/onboarding.js b/app/javascript/mastodon/actions/onboarding.js index a161c50ef..a1dd3a731 100644 --- a/app/javascript/mastodon/actions/onboarding.js +++ b/app/javascript/mastodon/actions/onboarding.js @@ -1,14 +1,8 @@ -import { openModal } from './modal'; import { changeSetting, saveSettings } from './settings'; -export function showOnboardingOnce() { - return (dispatch, getState) => { - const alreadySeen = getState().getIn(['settings', 'onboarded']); +export const INTRODUCTION_VERSION = 20181216044202; - if (!alreadySeen) { - dispatch(openModal('ONBOARDING')); - dispatch(changeSetting(['onboarded'], true)); - dispatch(saveSettings()); - } - }; +export const closeOnboarding = () => dispatch => { + dispatch(changeSetting(['introductionVersion'], INTRODUCTION_VERSION)); + dispatch(saveSettings()); }; diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js index b2b0265aa..2912540a0 100644 --- a/app/javascript/mastodon/containers/mastodon.js +++ b/app/javascript/mastodon/containers/mastodon.js @@ -1,11 +1,12 @@ import React from 'react'; -import { Provider } from 'react-redux'; +import { Provider, connect } from 'react-redux'; import PropTypes from 'prop-types'; import configureStore from '../store/configureStore'; -import { showOnboardingOnce } from '../actions/onboarding'; +import { INTRODUCTION_VERSION } from '../actions/onboarding'; import { BrowserRouter, Route } from 'react-router-dom'; import { ScrollContext } from 'react-router-scroll-4'; import UI from '../features/ui'; +import Introduction from '../features/introduction'; import { fetchCustomEmojis } from '../actions/custom_emojis'; import { hydrateStore } from '../actions/store'; import { connectUserStream } from '../actions/streaming'; @@ -18,11 +19,39 @@ addLocaleData(localeData); export const store = configureStore(); const hydrateAction = hydrateStore(initialState); -store.dispatch(hydrateAction); -// load custom emojis +store.dispatch(hydrateAction); store.dispatch(fetchCustomEmojis()); +const mapStateToProps = state => ({ + showIntroduction: state.getIn(['settings', 'introductionVersion'], 0) < INTRODUCTION_VERSION, +}); + +@connect(mapStateToProps) +class MastodonMount extends React.PureComponent { + + static propTypes = { + showIntroduction: PropTypes.bool, + }; + + render () { + const { showIntroduction } = this.props; + + if (showIntroduction) { + return ; + } + + return ( + + + + + + ); + } + +} + export default class Mastodon extends React.PureComponent { static propTypes = { @@ -31,14 +60,6 @@ export default class Mastodon extends React.PureComponent { componentDidMount() { this.disconnect = store.dispatch(connectUserStream()); - - // Desktop notifications - // Ask after 1 minute - if (typeof window.Notification !== 'undefined' && Notification.permission === 'default') { - window.setTimeout(() => Notification.requestPermission(), 60 * 1000); - } - - store.dispatch(showOnboardingOnce()); } componentWillUnmount () { @@ -54,11 +75,7 @@ export default class Mastodon extends React.PureComponent { return ( - - - - - + ); diff --git a/app/javascript/mastodon/features/introduction/index.js b/app/javascript/mastodon/features/introduction/index.js new file mode 100644 index 000000000..6e0617f72 --- /dev/null +++ b/app/javascript/mastodon/features/introduction/index.js @@ -0,0 +1,196 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ReactSwipeableViews from 'react-swipeable-views'; +import classNames from 'classnames'; +import { connect } from 'react-redux'; +import { FormattedMessage } from 'react-intl'; +import { closeOnboarding } from '../../actions/onboarding'; +import screenHello from '../../../images/screen_hello.svg'; +import screenFederation from '../../../images/screen_federation.svg'; +import screenInteractions from '../../../images/screen_interactions.svg'; +import logoTransparent from '../../../images/logo_transparent.svg'; + +const FrameWelcome = ({ domain, onNext }) => ( +
+
+ +
+ +
+

+

{domain} }} />

+
+ +
+ +
+
+); + +FrameWelcome.propTypes = { + domain: PropTypes.string.isRequired, + onNext: PropTypes.func.isRequired, +}; + +const FrameFederation = ({ onNext }) => ( +
+
+ +
+ +
+
+

+

+
+ +
+

+

+
+ +
+

+

+
+
+ +
+ +
+
+); + +FrameFederation.propTypes = { + onNext: PropTypes.func.isRequired, +}; + +const FrameInteractions = ({ onNext }) => ( +
+
+ +
+ +
+
+

+

+
+ +
+

+

+
+ +
+

+

+
+
+ +
+ +
+
+); + +FrameInteractions.propTypes = { + onNext: PropTypes.func.isRequired, +}; + +@connect(state => ({ domain: state.getIn(['meta', 'domain']) })) +export default class Introduction extends React.PureComponent { + + static propTypes = { + domain: PropTypes.string.isRequired, + dispatch: PropTypes.func.isRequired, + }; + + state = { + currentIndex: 0, + }; + + componentWillMount () { + this.pages = [ + , + , + , + ]; + } + + componentDidMount() { + window.addEventListener('keyup', this.handleKeyUp); + } + + componentWillUnmount() { + window.addEventListener('keyup', this.handleKeyUp); + } + + handleDot = (e) => { + const i = Number(e.currentTarget.getAttribute('data-index')); + e.preventDefault(); + this.setState({ currentIndex: i }); + } + + handlePrev = () => { + this.setState(({ currentIndex }) => ({ + currentIndex: Math.max(0, currentIndex - 1), + })); + } + + handleNext = () => { + const { pages } = this; + + this.setState(({ currentIndex }) => ({ + currentIndex: Math.min(currentIndex + 1, pages.length - 1), + })); + } + + handleSwipe = (index) => { + this.setState({ currentIndex: index }); + } + + handleFinish = () => { + this.props.dispatch(closeOnboarding()); + } + + handleKeyUp = ({ key }) => { + switch (key) { + case 'ArrowLeft': + this.handlePrev(); + break; + case 'ArrowRight': + this.handleNext(); + break; + } + } + + render () { + const { currentIndex } = this.state; + const { pages } = this; + + return ( +
+ + {pages.map((page, i) => ( +
{page}
+ ))} +
+ +
+ {pages.map((_, i) => ( +
+ ))} +
+
+ ); + } + +} diff --git a/app/javascript/mastodon/features/ui/components/modal_root.js b/app/javascript/mastodon/features/ui/components/modal_root.js index b3b1ea862..cc2ab6c8c 100644 --- a/app/javascript/mastodon/features/ui/components/modal_root.js +++ b/app/javascript/mastodon/features/ui/components/modal_root.js @@ -11,7 +11,6 @@ import BoostModal from './boost_modal'; import ConfirmationModal from './confirmation_modal'; import FocalPointModal from './focal_point_modal'; import { - OnboardingModal, MuteModal, ReportModal, EmbedModal, @@ -21,7 +20,6 @@ import { const MODAL_COMPONENTS = { 'MEDIA': () => Promise.resolve({ default: MediaModal }), - 'ONBOARDING': OnboardingModal, 'VIDEO': () => Promise.resolve({ default: VideoModal }), 'BOOST': () => Promise.resolve({ default: BoostModal }), 'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }), diff --git a/app/javascript/mastodon/features/ui/components/onboarding_modal.js b/app/javascript/mastodon/features/ui/components/onboarding_modal.js deleted file mode 100644 index 4a5b249c9..000000000 --- a/app/javascript/mastodon/features/ui/components/onboarding_modal.js +++ /dev/null @@ -1,324 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import ReactSwipeableViews from 'react-swipeable-views'; -import classNames from 'classnames'; -import Permalink from '../../../components/permalink'; -import ComposeForm from '../../compose/components/compose_form'; -import Search from '../../compose/components/search'; -import NavigationBar from '../../compose/components/navigation_bar'; -import ColumnHeader from './column_header'; -import { List as ImmutableList } from 'immutable'; -import { me } from '../../../initial_state'; - -const noop = () => { }; - -const messages = defineMessages({ - home_title: { id: 'column.home', defaultMessage: 'Home' }, - notifications_title: { id: 'column.notifications', defaultMessage: 'Notifications' }, - local_title: { id: 'column.community', defaultMessage: 'Local timeline' }, - federated_title: { id: 'column.public', defaultMessage: 'Federated timeline' }, -}); - -const PageOne = ({ acct, domain }) => ( -
-
-

-

-
- -
-
-
- -
- -
- @{acct}@{domain} -
-
- -

-
-
-); - -PageOne.propTypes = { - acct: PropTypes.string.isRequired, - domain: PropTypes.string.isRequired, -}; - -const PageTwo = ({ myAccount }) => ( -
-
-
- - - -
-
- -

-
-); - -PageTwo.propTypes = { - myAccount: ImmutablePropTypes.map.isRequired, -}; - -const PageThree = ({ myAccount }) => ( -
-
- - -
- -
-
- -

#illustration, introductions: #introductions }} />

-

-
-); - -PageThree.propTypes = { - myAccount: ImmutablePropTypes.map.isRequired, -}; - -const PageFour = ({ domain, intl }) => ( -
-
-
-
-
-

-
- -
-
-

-
-
- -
-
-
-
- -
-
-
-
- -

-
-
-); - -PageFour.propTypes = { - domain: PropTypes.string.isRequired, - intl: PropTypes.object.isRequired, -}; - -const PageSix = ({ admin, domain }) => { - let adminSection = ''; - - if (admin) { - adminSection = ( -

- @{admin.get('acct')} }} /> -
- }} /> -

- ); - } - - return ( -
-

- {adminSection} -

GitHub }} />

-

}} />

-

-
- ); -}; - -PageSix.propTypes = { - admin: ImmutablePropTypes.map, - domain: PropTypes.string.isRequired, -}; - -const mapStateToProps = state => ({ - myAccount: state.getIn(['accounts', me]), - admin: state.getIn(['accounts', state.getIn(['meta', 'admin'])]), - domain: state.getIn(['meta', 'domain']), -}); - -export default @connect(mapStateToProps) -@injectIntl -class OnboardingModal extends React.PureComponent { - - static propTypes = { - onClose: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - myAccount: ImmutablePropTypes.map.isRequired, - domain: PropTypes.string.isRequired, - admin: ImmutablePropTypes.map, - }; - - state = { - currentIndex: 0, - }; - - componentWillMount() { - const { myAccount, admin, domain, intl } = this.props; - this.pages = [ - , - , - , - , - , - ]; - }; - - componentDidMount() { - window.addEventListener('keyup', this.handleKeyUp); - } - - componentWillUnmount() { - window.addEventListener('keyup', this.handleKeyUp); - } - - handleSkip = (e) => { - e.preventDefault(); - this.props.onClose(); - } - - handleDot = (e) => { - const i = Number(e.currentTarget.getAttribute('data-index')); - e.preventDefault(); - this.setState({ currentIndex: i }); - } - - handlePrev = () => { - this.setState(({ currentIndex }) => ({ - currentIndex: Math.max(0, currentIndex - 1), - })); - } - - handleNext = () => { - const { pages } = this; - this.setState(({ currentIndex }) => ({ - currentIndex: Math.min(currentIndex + 1, pages.length - 1), - })); - } - - handleSwipe = (index) => { - this.setState({ currentIndex: index }); - } - - handleKeyUp = ({ key }) => { - switch (key) { - case 'ArrowLeft': - this.handlePrev(); - break; - case 'ArrowRight': - this.handleNext(); - break; - } - } - - handleClose = () => { - this.props.onClose(); - } - - render () { - const { pages } = this; - const { currentIndex } = this.state; - const hasMore = currentIndex < pages.length - 1; - - const nextOrDoneBtn = hasMore ? ( - - ) : ( - - ); - - return ( -
- - {pages.map((page, i) => { - const className = classNames('onboarding-modal__page__wrapper', `onboarding-modal__page__wrapper-${i}`, { - 'onboarding-modal__page__wrapper--active': i === currentIndex, - }); - - return ( -
{page}
- ); - })} -
- -
-
- -
- -
- {pages.map((_, i) => { - const className = classNames('onboarding-modal__dot', { - active: i === currentIndex, - }); - - return ( -
- ); - })} -
- -
- {nextOrDoneBtn} -
-
-
- ); - } - -} diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index 662375a76..e11235a81 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -294,6 +294,7 @@ class UI extends React.PureComponent { componentWillMount () { window.addEventListener('beforeunload', this.handleBeforeUnload, false); + document.addEventListener('dragenter', this.handleDragEnter, false); document.addEventListener('dragover', this.handleDragOver, false); document.addEventListener('drop', this.handleDrop, false); @@ -304,8 +305,13 @@ class UI extends React.PureComponent { navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage); } + if (typeof window.Notification !== 'undefined' && Notification.permission === 'default') { + window.setTimeout(() => Notification.requestPermission(), 120 * 1000); + } + this.props.dispatch(expandHomeTimeline()); this.props.dispatch(expandNotifications()); + setTimeout(() => this.props.dispatch(fetchFilters()), 500); } diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 2a15c052f..235fd2a07 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -102,10 +102,6 @@ export function Mutes () { return import(/* webpackChunkName: "features/mutes" */'../../mutes'); } -export function OnboardingModal () { - return import(/* webpackChunkName: "modals/onboarding_modal" */'../components/onboarding_modal'); -} - export function MuteModal () { return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal'); } diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss index 0990a4f25..4bce74187 100644 --- a/app/javascript/styles/application.scss +++ b/app/javascript/styles/application.scss @@ -16,6 +16,7 @@ @import 'mastodon/stream_entries'; @import 'mastodon/boost'; @import 'mastodon/components'; +@import 'mastodon/introduction'; @import 'mastodon/modal'; @import 'mastodon/emoji_picker'; @import 'mastodon/about'; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 1c1b8c506..d2b3baaf0 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3835,25 +3835,6 @@ a.status-card.compact:hover { flex-direction: column; } -.onboarding-modal__pager { - height: 80vh; - width: 80vw; - max-width: 520px; - max-height: 470px; - - .react-swipeable-view-container > div { - width: 100%; - height: 100%; - box-sizing: border-box; - display: none; - flex-direction: column; - align-items: center; - justify-content: center; - display: flex; - user-select: text; - } -} - .error-modal__body { height: 80vh; width: 80vw; @@ -3887,22 +3868,6 @@ a.status-card.compact:hover { text-align: center; } -@media screen and (max-width: 550px) { - .onboarding-modal { - width: 100%; - height: 100%; - border-radius: 0; - } - - .onboarding-modal__pager { - width: 100%; - height: auto; - max-width: none; - max-height: none; - flex: 1 1 auto; - } -} - .onboarding-modal__paginator, .error-modal__footer { flex: 0 0 auto; @@ -3951,124 +3916,6 @@ a.status-card.compact:hover { justify-content: center; } -.onboarding-modal__dots { - flex: 1 1 auto; - display: flex; - align-items: center; - justify-content: center; -} - -.onboarding-modal__dot { - width: 14px; - height: 14px; - border-radius: 14px; - background: darken($ui-secondary-color, 16%); - margin: 0 3px; - cursor: pointer; - - &:hover { - background: darken($ui-secondary-color, 18%); - } - - &.active { - cursor: default; - background: darken($ui-secondary-color, 24%); - } -} - -.onboarding-modal__page__wrapper { - pointer-events: none; - padding: 25px; - padding-bottom: 0; - - &.onboarding-modal__page__wrapper--active { - pointer-events: auto; - } -} - -.onboarding-modal__page { - cursor: default; - line-height: 21px; - - h1 { - font-size: 18px; - font-weight: 500; - color: $inverted-text-color; - margin-bottom: 20px; - } - - a { - color: $highlight-text-color; - - &:hover, - &:focus, - &:active { - color: lighten($highlight-text-color, 4%); - } - } - - .navigation-bar a { - color: inherit; - } - - p { - font-size: 16px; - color: $lighter-text-color; - margin-top: 10px; - margin-bottom: 10px; - - &:last-child { - margin-bottom: 0; - } - - strong { - font-weight: 500; - background: $ui-base-color; - color: $secondary-text-color; - border-radius: 4px; - font-size: 14px; - padding: 3px 6px; - - @each $lang in $cjk-langs { - &:lang(#{$lang}) { - font-weight: 700; - } - } - } - } -} - -.onboarding-modal__page__wrapper-0 { - background: url('../images/elephant_ui_greeting.svg') no-repeat left bottom / auto 250px; - height: 100%; - padding: 0; -} - -.onboarding-modal__page-one { - &__lead { - padding: 65px; - padding-top: 45px; - padding-bottom: 0; - margin-bottom: 10px; - - h1 { - font-size: 26px; - line-height: 36px; - margin-bottom: 8px; - } - - p { - margin-bottom: 0; - } - } - - &__extra { - padding-right: 65px; - padding-left: 185px; - text-align: center; - } -} - .display-case { text-align: center; font-size: 15px; @@ -4091,92 +3938,6 @@ a.status-card.compact:hover { } } -.onboarding-modal__page-two, -.onboarding-modal__page-three, -.onboarding-modal__page-four, -.onboarding-modal__page-five { - p { - text-align: left; - } - - .figure { - background: darken($ui-base-color, 8%); - color: $secondary-text-color; - margin-bottom: 20px; - border-radius: 4px; - padding: 10px; - text-align: center; - font-size: 14px; - box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.3); - - .onboarding-modal__image { - border-radius: 4px; - margin-bottom: 10px; - } - - &.non-interactive { - pointer-events: none; - text-align: left; - } - } -} - -.onboarding-modal__page-four__columns { - .row { - display: flex; - margin-bottom: 20px; - - & > div { - flex: 1 1 0; - margin: 0 10px; - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - - p { - text-align: center; - } - } - - &:last-child { - margin-bottom: 0; - } - } - - .column-header { - color: $primary-text-color; - } -} - -@media screen and (max-width: 320px) and (max-height: 600px) { - .onboarding-modal__page p { - font-size: 14px; - line-height: 20px; - } - - .onboarding-modal__page-two .figure, - .onboarding-modal__page-three .figure, - .onboarding-modal__page-four .figure, - .onboarding-modal__page-five .figure { - font-size: 12px; - margin-bottom: 10px; - } - - .onboarding-modal__page-four__columns .row { - margin-bottom: 10px; - } - - .onboarding-modal__page-four__columns .column-header { - padding: 5px; - font-size: 12px; - } -} - .onboard-sliders { display: inline-block; max-width: 30px; diff --git a/app/javascript/styles/mastodon/introduction.scss b/app/javascript/styles/mastodon/introduction.scss new file mode 100644 index 000000000..222d8f60e --- /dev/null +++ b/app/javascript/styles/mastodon/introduction.scss @@ -0,0 +1,153 @@ +.introduction { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + @media screen and (max-width: 920px) { + background: darken($ui-base-color, 8%); + display: block !important; + } + + &__pager { + background: darken($ui-base-color, 8%); + box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); + overflow: hidden; + } + + &__pager, + &__frame { + border-radius: 10px; + width: 50vw; + min-width: 920px; + + @media screen and (max-width: 920px) { + min-width: 0; + width: 100%; + border-radius: 0; + box-shadow: none; + } + } + + &__frame-wrapper { + opacity: 0; + transition: opacity 500ms linear; + + &.active { + opacity: 1; + transition: opacity 50ms linear; + } + } + + &__frame { + overflow: hidden; + } + + &__illustration { + height: 50vh; + + @media screen and (max-width: 630px) { + height: auto; + } + + img { + object-fit: cover; + display: block; + margin: 0; + width: 100%; + height: 100%; + } + } + + &__text { + border-top: 2px solid $ui-highlight-color; + + &--columnized { + display: flex; + + & > div { + flex: 1 1 33.33%; + text-align: center; + padding: 25px; + padding-bottom: 30px; + } + + @media screen and (max-width: 630px) { + display: block; + padding: 15px 0; + padding-bottom: 20px; + + & > div { + padding: 10px 25px; + } + } + } + + h3 { + font-size: 24px; + line-height: 1.5; + font-weight: 700; + margin-bottom: 10px; + } + + p { + font-size: 16px; + line-height: 24px; + font-weight: 400; + color: $darker-text-color; + + code { + display: inline-block; + background: darken($ui-base-color, 8%); + font-size: 15px; + border: 1px solid lighten($ui-base-color, 8%); + border-radius: 2px; + padding: 1px 3px; + } + } + + &--centered { + padding: 25px; + padding-bottom: 30px; + text-align: center; + } + } + + &__dots { + display: flex; + align-items: center; + justify-content: center; + padding: 25px; + + @media screen and (max-width: 630px) { + display: none; + } + } + + &__dot { + width: 14px; + height: 14px; + border-radius: 14px; + border: 1px solid $ui-highlight-color; + background: transparent; + margin: 0 3px; + cursor: pointer; + + &:hover { + background: lighten($ui-base-color, 8%); + } + + &.active { + cursor: default; + background: $ui-highlight-color; + } + } + + &__action { + padding: 25px; + padding-top: 0; + display: flex; + align-items: center; + justify-content: center; + } +} -- cgit From 4ede51743e5b9121a49e9131f91cf012fab410f8 Mon Sep 17 00:00:00 2001 From: ThibG Date: Mon, 17 Dec 2018 17:02:59 +0100 Subject: Minor scrollable list fixes (#9551) * Make sure loading indicator has enough vertical space * Respect reduce_motion setting for loading indicator --- app/javascript/mastodon/features/account_gallery/index.js | 2 +- app/javascript/styles/mastodon/components.scss | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'app/javascript/styles') diff --git a/app/javascript/mastodon/features/account_gallery/index.js b/app/javascript/mastodon/features/account_gallery/index.js index 0d66868ed..96051818b 100644 --- a/app/javascript/mastodon/features/account_gallery/index.js +++ b/app/javascript/mastodon/features/account_gallery/index.js @@ -103,7 +103,7 @@ class AccountGallery extends ImmutablePureComponent { ); } - if (hasMore) { + if (hasMore && !(isLoading && medias.size === 0)) { loadOlder = ; } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index d2b3baaf0..595472263 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2153,6 +2153,7 @@ a.account__display-name { &__append { flex: 1 1 auto; position: relative; + min-height: 120px; } } @@ -2946,7 +2947,6 @@ a.status-card.compact:hover { transform: translateX(-50%); margin: 82px 0 0 50%; white-space: nowrap; - animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000); } } @@ -2955,11 +2955,20 @@ a.status-card.compact:hover { top: 50%; left: 50%; transform: translate(-50%, -50%); - width: 0; - height: 0; + width: 42px; + height: 42px; box-sizing: border-box; + background-color: transparent; border: 0 solid lighten($ui-base-color, 26%); + border-width: 6px; border-radius: 50%; +} + +.no-reduce-motion .loading-indicator span { + animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000); +} + +.no-reduce-motion .loading-indicator__figure { animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.610, 0.355, 1.000); } -- cgit From 12ab15e584e78d209b59a893405a0cde83f49035 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 17 Dec 2018 21:08:40 +0100 Subject: Make notifications quick-filter use consistent style with profile tabs (#9554) --- app/javascript/styles/mastodon/components.scss | 53 ++++---------------------- 1 file changed, 7 insertions(+), 46 deletions(-) (limited to 'app/javascript/styles') diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 595472263..40a1e3fae 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1484,52 +1484,6 @@ a.account__display-name { } } -.notification__filter-bar { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - background: $ui-base-color; - - & > button { - position: relative; - flex-grow: 1; - color: $primary-text-color; - padding: 10px 5px 12px; - text-decoration: none; - font-weight: 400; - font-size: 15px; - line-height: 18px; - background: darken($ui-base-color, 4%); - border: 0; - border-bottom: 1px solid lighten($ui-base-color, 8%); - cursor: default; - - &.active { - color: $secondary-text-color; - - &::before, - &::after { - display: block; - content: ""; - position: absolute; - bottom: 0; - left: 50%; - width: 0; - height: 0; - transform: translateX(-50%); - border-style: solid; - border-width: 0 10px 10px; - border-color: transparent transparent lighten($ui-base-color, 8%); - } - - &::after { - bottom: -1px; - border-color: transparent transparent $ui-base-color; - } - } - } -} - .notification__message { margin: 0 10px 0 68px; padding: 8px 0 0; @@ -4846,12 +4800,19 @@ a.status-card.compact:hover { } } +.notification__filter-bar, .account__section-headline { background: darken($ui-base-color, 4%); border-bottom: 1px solid lighten($ui-base-color, 8%); cursor: default; display: flex; + button { + background: darken($ui-base-color, 4%); + border: 0; + } + + button, a { display: block; flex: 1 1 auto; -- cgit