From 8b1b901cc0953b74a94191b72933dccd854105ce Mon Sep 17 00:00:00 2001 From: Sasha Sorokin Date: Fri, 24 Jan 2020 14:50:49 -0500 Subject: [PATCH 1/8] Evenly spread space between tabs (#12944) This commit fixes uneven spread of space between the tabs in profiles or notifications (filters). The problem was that links and buttons shown as blocks had their width determined according to the content inside of them, so if one tab has more text content than another, it is going to take over others space, which is uneven and results in incorrectly aligned (?) tabs display. By specifying the size of 100% for each tab, parent container will be forced to divide available space by the number of elements and evenly give each child fixed space, "text-align: center" then doing its best job to keep tabs text centered in that space. This relatively fixes the problem, but will introduce another one - when the block has more content that its width allows to have, in this scenario the text should be wrapped or will be displayed over the other elements, but I see this more as translators' problem. Still, for this case "overflow: hidden" is added and any unfitting text will be cut out. --- app/javascript/styles/mastodon/components.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 922d48ad74..8147ef28d5 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -5731,6 +5731,8 @@ a.status-card.compact:hover { text-align: center; text-decoration: none; position: relative; + overflow: hidden; + width: 100%; &.active { color: $secondary-text-color; From 6598ab989b9d8cd71cc72606f24fc987c348144d Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Fri, 24 Jan 2020 13:51:33 -0600 Subject: [PATCH 2/8] minor server-sent events fixes (#12945) * Send output on the server-sent events stream immediately so the client sees that it was successfully opened even if it doesn't have any messages. Fix transparent SSE streaming for the public:local and hashtag:local stream types. * Tell caches to never store server-sent events. --- app/javascript/mastodon/stream.js | 1 + streaming/index.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/app/javascript/mastodon/stream.js b/app/javascript/mastodon/stream.js index fe965bcb0e..0cb2b228f3 100644 --- a/app/javascript/mastodon/stream.js +++ b/app/javascript/mastodon/stream.js @@ -92,6 +92,7 @@ export default function getStream(streamingAPIBaseURL, accessToken, stream, { co return ws; } + stream = stream.replace(/:/g, '/'); params.push(`access_token=${accessToken}`); const es = new EventSource(`${streamingAPIBaseURL}/api/v1/streaming/${stream}?${params.join('&')}`); diff --git a/streaming/index.js b/streaming/index.js index 304e7e0465..0a19c74a63 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -436,8 +436,11 @@ const startWorker = (workerId) => { const accountId = req.accountId || req.remoteAddress; res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-store'); res.setHeader('Transfer-Encoding', 'chunked'); + res.write(':)\n'); + const heartbeat = setInterval(() => res.write(':thump\n'), 15000); req.on('close', () => { From bfc08eca51d3530fba1f7d9a826c9ba92e3f41ee Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 24 Jan 2020 22:08:24 +0100 Subject: [PATCH 3/8] Fix type error in announcement reaction update event payload (#12946) --- app/workers/publish_announcement_reaction_worker.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/workers/publish_announcement_reaction_worker.rb b/app/workers/publish_announcement_reaction_worker.rb index 6f3b6dc5b6..e01deb64dd 100644 --- a/app/workers/publish_announcement_reaction_worker.rb +++ b/app/workers/publish_announcement_reaction_worker.rb @@ -10,7 +10,7 @@ class PublishAnnouncementReactionWorker reaction, = announcement.announcement_reactions.where(name: name).group(:announcement_id, :name, :custom_emoji_id).select('name, custom_emoji_id, count(*) as count, false as me') reaction ||= announcement.announcement_reactions.new(name: name) - payload = InlineRenderer.render(reaction, nil, :reaction).tap { |h| h[:announcement_id] = announcement_id } + payload = InlineRenderer.render(reaction, nil, :reaction).tap { |h| h[:announcement_id] = announcement_id.to_s } payload = Oj.dump(event: :'announcement.reaction', payload: payload) Account.joins(:user).where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago).find_each do |account| From 51f376aee3a6d51800d6b6c628aaf3d0f621fd9b Mon Sep 17 00:00:00 2001 From: Sasha Sorokin Date: Fri, 24 Jan 2020 16:37:04 -0500 Subject: [PATCH 4/8] Fix unlocalized dropdown button title (#12947) In detailed status component, "More" action bar button wasn't localized. This commit fixes it according to previously used code. --- .../mastodon/features/status/components/action_bar.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/status/components/action_bar.js b/app/javascript/mastodon/features/status/components/action_bar.js index bf6469f2fc..657d2bb1c5 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.js +++ b/app/javascript/mastodon/features/status/components/action_bar.js @@ -19,6 +19,7 @@ const messages = defineMessages({ cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' }, + more: { id: 'status.more', defaultMessage: 'More' }, mute: { id: 'status.mute', defaultMessage: 'Mute @{name}' }, muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' }, unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' }, @@ -275,7 +276,7 @@ class ActionBar extends React.PureComponent {
- +
); From b169901439cdce2cd6689a45bf93c069407b4822 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 25 Jan 2020 04:20:06 +0100 Subject: [PATCH 5/8] Change font size of announcements to be the same as statuses (#12949) --- app/javascript/styles/mastodon/components.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 8147ef28d5..6c412bc892 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -6654,6 +6654,10 @@ noscript { padding: 15px; padding-right: 15px + 18px; position: relative; + font-size: 15px; + line-height: 20px; + word-wrap: break-word; + font-weight: 400; &__range { display: block; From fb1df3d5d51f129049b99b215ce17aa6cc14c794 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 25 Jan 2020 05:22:35 +0100 Subject: [PATCH 6/8] Fix user disabling changing activity timestamps, fix nil error (#12943) --- app/models/user.rb | 6 ++---- spec/models/user_spec.rb | 15 +-------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 058a8d5f87..85ee5cd064 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -128,9 +128,7 @@ class User < ApplicationRecord end def disable! - update!(disabled: true, - last_sign_in_at: current_sign_in_at, - current_sign_in_at: nil) + update!(disabled: true) end def enable! @@ -301,7 +299,7 @@ class User < ApplicationRecord arr << [current_sign_in_at, current_sign_in_ip] if current_sign_in_ip.present? arr << [last_sign_in_at, last_sign_in_ip] if last_sign_in_ip.present? - arr.sort_by(&:first).uniq(&:last).reverse! + arr.sort_by { |pair| pair.first || Time.now.utc }.uniq(&:last).reverse! end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d7c0b53593..5686ec909e 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -322,20 +322,7 @@ RSpec.describe User, type: :model do end it 'disables user' do - expect(user).to have_attributes(disabled: true, current_sign_in_at: nil, last_sign_in_at: current_sign_in_at) - end - end - - describe '#disable!' do - subject(:user) { Fabricate(:user, disabled: false, current_sign_in_at: current_sign_in_at, last_sign_in_at: nil) } - let(:current_sign_in_at) { Time.zone.now } - - before do - user.disable! - end - - it 'disables user' do - expect(user).to have_attributes(disabled: true, current_sign_in_at: nil, last_sign_in_at: current_sign_in_at) + expect(user).to have_attributes(disabled: true) end end From 8ca6f2d3b21f0da3d13209ce53d7c5095631a6a3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 25 Jan 2020 05:23:05 +0100 Subject: [PATCH 7/8] Add number animations (#12948) --- .../mastodon/components/animated_number.js | 47 +++++++++++++++++++ .../components/announcements.js | 5 +- .../status/components/detailed_status.js | 11 +++-- .../styles/mastodon/components.scss | 12 ++++- 4 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 app/javascript/mastodon/components/animated_number.js diff --git a/app/javascript/mastodon/components/animated_number.js b/app/javascript/mastodon/components/animated_number.js new file mode 100644 index 0000000000..2d359fbc60 --- /dev/null +++ b/app/javascript/mastodon/components/animated_number.js @@ -0,0 +1,47 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedNumber } from 'react-intl'; +import TransitionMotion from 'react-motion/lib/TransitionMotion'; +import spring from 'react-motion/lib/spring'; +import { reduceMotion } from 'mastodon/initial_state'; + +export default class AnimatedNumber extends React.PureComponent { + + static propTypes = { + value: PropTypes.number.isRequired, + }; + + willEnter () { + return { y: -1 }; + } + + willLeave () { + return { y: spring(1, { damping: 35, stiffness: 400 }) }; + } + + render () { + const { value } = this.props; + + if (reduceMotion) { + return ; + } + + const styles = [{ + key: value, + style: { y: spring(0, { damping: 35, stiffness: 400 }) }, + }]; + + return ( + + {items => ( + + {items.map(({ key, style }) => ( + 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}> + ))} + + )} + + ); + } + +} diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.js b/app/javascript/mastodon/features/getting_started/components/announcements.js index ee444e3f03..18b1de1272 100644 --- a/app/javascript/mastodon/features/getting_started/components/announcements.js +++ b/app/javascript/mastodon/features/getting_started/components/announcements.js @@ -5,13 +5,14 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import IconButton from 'mastodon/components/icon_button'; import Icon from 'mastodon/components/icon'; -import { defineMessages, injectIntl, FormattedMessage, FormattedDate, FormattedNumber } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage, FormattedDate } from 'react-intl'; import { autoPlayGif } from 'mastodon/initial_state'; import elephantUIPlane from 'mastodon/../images/elephant_ui_plane.svg'; import { mascot } from 'mastodon/initial_state'; import unicodeMapping from 'mastodon/features/emoji/emoji_unicode_mapping_light'; import classNames from 'classnames'; import EmojiPickerDropdown from 'mastodon/features/compose/containers/emoji_picker_dropdown_container'; +import AnimatedNumber from 'mastodon/components/animated_number'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -225,7 +226,7 @@ class Reaction extends ImmutablePureComponent { return ( ); } diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index d5bc827359..2fec247c16 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -6,7 +6,7 @@ import DisplayName from '../../../components/display_name'; import StatusContent from '../../../components/status_content'; import MediaGallery from '../../../components/media_gallery'; import { Link } from 'react-router-dom'; -import { FormattedDate, FormattedNumber } from 'react-intl'; +import { FormattedDate } from 'react-intl'; import Card from './card'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Video from '../../video'; @@ -14,6 +14,7 @@ import Audio from '../../audio'; import scheduleIdleTask from '../../ui/util/schedule_idle_task'; import classNames from 'classnames'; import Icon from 'mastodon/components/icon'; +import AnimatedNumber from 'mastodon/components/animated_number'; export default class DetailedStatus extends ImmutablePureComponent { @@ -172,7 +173,7 @@ export default class DetailedStatus extends ImmutablePureComponent { - + ); @@ -181,7 +182,7 @@ export default class DetailedStatus extends ImmutablePureComponent { - + ); @@ -192,7 +193,7 @@ export default class DetailedStatus extends ImmutablePureComponent { - + ); @@ -201,7 +202,7 @@ export default class DetailedStatus extends ImmutablePureComponent { - + ); diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 6c412bc892..1e1000ff3c 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3,6 +3,14 @@ -ms-overflow-style: -ms-autohiding-scrollbar; } +.animated-number { + display: inline-flex; + flex-direction: column; + align-items: stretch; + overflow: hidden; + position: relative; +} + .link-button { display: block; font-size: 15px; @@ -6754,10 +6762,10 @@ noscript { &.active { transition: all 100ms ease-in; transition-property: background-color, color; - background-color: mix(lighten($ui-base-color, 12%), $ui-highlight-color, 90%); + background-color: mix(lighten($ui-base-color, 12%), $ui-highlight-color, 80%); .reactions-bar__item__count { - color: $highlight-text-color; + color: lighten($highlight-text-color, 8%); } } } From 150c13c4e0ed0a73c2fd65539c952c2015f2b0be Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 25 Jan 2020 05:23:33 +0100 Subject: [PATCH 8/8] Add limit of 8 different reaction types per announcement (#12950) --- .../features/getting_started/components/announcements.js | 2 +- app/validators/reaction_validator.rb | 7 +++++++ config/locales/en.yml | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.js b/app/javascript/mastodon/features/getting_started/components/announcements.js index 18b1de1272..975db02656 100644 --- a/app/javascript/mastodon/features/getting_started/components/announcements.js +++ b/app/javascript/mastodon/features/getting_started/components/announcements.js @@ -265,7 +265,7 @@ class ReactionsBar extends ImmutablePureComponent { /> ))} - } /> + {visibleReactions.size < 8 && } />} ); } diff --git a/app/validators/reaction_validator.rb b/app/validators/reaction_validator.rb index de0f2c94b9..be899c89d0 100644 --- a/app/validators/reaction_validator.rb +++ b/app/validators/reaction_validator.rb @@ -3,10 +3,13 @@ class ReactionValidator < ActiveModel::Validator SUPPORTED_EMOJIS = Oj.load(File.read(Rails.root.join('app', 'javascript', 'mastodon', 'features', 'emoji', 'emoji_map.json'))).keys.freeze + LIMIT = 8 + def validate(reaction) return if reaction.name.blank? || reaction.custom_emoji_id.present? reaction.errors.add(:name, I18n.t('reactions.errors.unrecognized_emoji')) unless unicode_emoji?(reaction.name) + reaction.errors.add(:base, I18n.t('reactions.errors.limit_reached')) if limit_reached?(reaction) end private @@ -14,4 +17,8 @@ class ReactionValidator < ActiveModel::Validator def unicode_emoji?(name) SUPPORTED_EMOJIS.include?(name) end + + def limit_reached?(reaction) + reaction.announcement.announcement_reactions.where.not(name: reaction.name).count('distinct name') >= LIMIT + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index bb9084b32d..0ba5730201 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -951,6 +951,7 @@ en: public_timelines: Public timelines reactions: errors: + limit_reached: Limit of different reactions reached unrecognized_emoji: is not a recognized emoji relationships: activity: Account activity