diff --git a/Gemfile b/Gemfile index bc51e7694..b83284823 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'streamio-ffmpeg', '~> 3.0' gem 'active_model_serializers', '~> 0.10' gem 'addressable', '~> 2.6' -gem 'bootsnap', '~> 1.3', require: false +gem 'bootsnap', '~> 1.4', require: false gem 'browser' gem 'charlock_holmes', '~> 0.7.6' gem 'iso-639' diff --git a/Gemfile.lock b/Gemfile.lock index a37ff9989..40f4149c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -92,13 +92,13 @@ GEM aws-sigv4 (1.0.3) bcrypt (3.1.12) benchmark-ips (2.7.2) - better_errors (2.5.0) + better_errors (2.5.1) coderay (>= 1.0.0) erubi (>= 1.0.0) rack (>= 0.9.0) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) - bootsnap (1.3.2) + bootsnap (1.4.0) msgpack (~> 1.0) brakeman (4.4.0) browser (2.5.3) @@ -205,7 +205,7 @@ GEM tzinfo excon (0.62.0) fabrication (2.20.1) - faker (1.9.1) + faker (1.9.3) i18n (>= 0.7) faraday (0.15.0) multipart-post (>= 1.2, < 3) @@ -347,7 +347,7 @@ GEM mini_mime (1.0.1) mini_portile2 (2.4.0) minitest (5.11.3) - msgpack (1.2.4) + msgpack (1.2.6) multi_json (1.13.1) multipart-post (2.0.0) necromancer (0.4.0) @@ -402,7 +402,7 @@ GEM pg (1.1.4) pghero (2.2.0) activerecord - pkg-config (1.3.2) + pkg-config (1.3.3) powerpack (0.1.2) premailer (1.11.1) addressable @@ -565,7 +565,7 @@ GEM rufus-scheduler (~> 3.2) sidekiq (>= 3) tilt (>= 1.4.0) - sidekiq-unique-jobs (6.0.8) + sidekiq-unique-jobs (6.0.9) concurrent-ruby (~> 1.0, >= 1.0.5) sidekiq (>= 4.0, < 6.0) thor (~> 0) @@ -662,7 +662,7 @@ DEPENDENCIES aws-sdk-s3 (~> 1.30) better_errors (~> 2.5) binding_of_caller (~> 0.7) - bootsnap (~> 1.3) + bootsnap (~> 1.4) brakeman (~> 4.4) browser bullet (~> 5.9) diff --git a/app/chewy/statuses_index.rb b/app/chewy/statuses_index.rb index d3104172c..eafc1818b 100644 --- a/app/chewy/statuses_index.rb +++ b/app/chewy/statuses_index.rb @@ -31,7 +31,7 @@ class StatusesIndex < Chewy::Index }, } - define_type ::Status.unscoped.without_reblogs do + define_type ::Status.unscoped.without_reblogs.includes(:media_attachments) do crutch :mentions do |collection| data = ::Mention.where(status_id: collection.map(&:id)).pluck(:status_id, :account_id) data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) } @@ -50,7 +50,7 @@ class StatusesIndex < Chewy::Index root date_detection: false do field :account_id, type: 'long' - field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].join("\n\n") } do + field :text, type: 'text', value: ->(status) { [status.spoiler_text, Formatter.instance.plaintext(status)].concat(status.media_attachments.map(&:description)).join("\n\n") } do field :stemmed, type: 'text', analyzer: 'content' end diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index 11436d7c5..efe29b53f 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -29,6 +29,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController resource.invite_code = params[:invite_code] if resource.invite_code.blank? resource.agreement = true + resource.current_sign_in_ip = request.remote_ip if resource.current_sign_in_ip.nil? resource.build_account if resource.account.nil? end diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 7a3ceca78..e868b45c0 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -4,7 +4,7 @@ module SettingsHelper HUMAN_LOCALES = { en: 'English', ar: 'العربية', - ast: 'l\'asturianu', + ast: 'Asturianu', bg: 'Български', ca: 'Català', co: 'Corsu', @@ -30,16 +30,16 @@ module SettingsHelper ja: '日本語', ka: 'ქართული', ko: '한국어', - lv: 'Latviešu valoda', + lv: 'Latviešu', ml: 'മലയാളം', - ms: 'بهاس ملايو', + ms: 'Bahasa Melayu', nl: 'Nederlands', no: 'Norsk', oc: 'Occitan', - pl: 'Polszczyzna', + pl: 'Polski', pt: 'Português', 'pt-BR': 'Português do Brasil', - ro: 'Limba română', + ro: 'Română', ru: 'Русский', sk: 'Slovenčina', sl: 'Slovenščina', @@ -49,7 +49,7 @@ module SettingsHelper sv: 'Svenska', ta: 'தமிழ்', te: 'తెలుగు', - th: 'ภาษาไทย', + th: 'ไทย', tr: 'Türkçe', uk: 'Українська', zh: '中文', diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js index 82936c838..dc0ffee85 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/components/column_settings.js @@ -1,10 +1,15 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { injectIntl, FormattedMessage } from 'react-intl'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import Toggle from 'react-toggle'; import AsyncSelect from 'react-select/lib/Async'; +const messages = defineMessages({ + placeholder: { id: 'hashtag.column_settings.select.placeholder', defaultMessage: 'Enter hashtags…' }, + noOptions: { id: 'hashtag.column_settings.select.no_options_message', defaultMessage: 'No suggestions found' }, +}); + @injectIntl export default class ColumnSettings extends React.PureComponent { @@ -25,6 +30,7 @@ export default class ColumnSettings extends React.PureComponent { tags (mode) { let tags = this.props.settings.getIn(['tags', mode]) || []; + if (tags.toJSON) { return tags.toJSON(); } else { @@ -32,33 +38,36 @@ export default class ColumnSettings extends React.PureComponent { } }; - onSelect = (mode) => { - return (value) => { - this.props.onChange(['tags', mode], value); - }; - }; + onSelect = mode => value => this.props.onChange(['tags', mode], value); onToggle = () => { if (this.state.open && this.hasTags()) { this.props.onChange('tags', {}); } + this.setState({ open: !this.state.open }); }; + noOptionsMessage = () => this.props.intl.formatMessage(messages.noOptions); + modeSelect (mode) { return ( -
- {this.modeLabel(mode)} +
+ + {this.modeLabel(mode)} + +
); @@ -66,11 +75,15 @@ export default class ColumnSettings extends React.PureComponent { modeLabel (mode) { switch(mode) { - case 'any': return ; - case 'all': return ; - case 'none': return ; + case 'any': + return ; + case 'all': + return ; + case 'none': + return ; + default: + return ''; } - return ''; }; render () { @@ -78,23 +91,21 @@ export default class ColumnSettings extends React.PureComponent {
- + +
- {this.state.open && + + {this.state.open && (
{this.modeSelect('any')} {this.modeSelect('all')} {this.modeSelect('none')}
- } + )}
); } diff --git a/app/javascript/flavours/glitch/styles/_mixins.scss b/app/javascript/flavours/glitch/styles/_mixins.scss index c46d7260d..586802185 100644 --- a/app/javascript/flavours/glitch/styles/_mixins.scss +++ b/app/javascript/flavours/glitch/styles/_mixins.scss @@ -82,3 +82,34 @@ font-size: 16px; } } + +@mixin search-popout() { + background: $simple-background-color; + border-radius: 4px; + padding: 10px 14px; + padding-bottom: 14px; + margin-top: 10px; + color: $light-text-color; + box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); + + h4 { + text-transform: uppercase; + color: $light-text-color; + font-size: 13px; + font-weight: 500; + margin-bottom: 10px; + } + + li { + padding: 4px 0; + } + + ul { + margin-bottom: 10px; + } + + em { + font-weight: 500; + color: $inverted-text-color; + } +} diff --git a/app/javascript/flavours/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss index 302de020b..329482458 100644 --- a/app/javascript/flavours/glitch/styles/about.scss +++ b/app/javascript/flavours/glitch/styles/about.scss @@ -49,15 +49,9 @@ $small-breakpoint: 960px; } } + strong, em { - display: inline; - margin: 0; - padding: 0; font-weight: 700; - background: transparent; - font-family: inherit; - font-size: inherit; - line-height: inherit; color: lighten($darker-text-color, 10%); } @@ -798,7 +792,7 @@ $small-breakpoint: 960px; width: 100%; display: flex; flex-direction: row-reverse; - flex-wrap: wrap; + flex-wrap: nowrap; justify-content: space-between; align-items: center; } @@ -848,14 +842,7 @@ $small-breakpoint: 960px; } strong { - display: inline; - margin: 0; - padding: 0; - font-weight: 700; - background: transparent; - font-family: inherit; - font-size: inherit; - line-height: inherit; + font-weight: 500; color: lighten($darker-text-color, 10%); } diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss index ce6cc8b29..0b7b58bb0 100644 --- a/app/javascript/flavours/glitch/styles/components/accounts.scss +++ b/app/javascript/flavours/glitch/styles/components/accounts.scss @@ -339,14 +339,41 @@ display: block; font-weight: 500; margin-bottom: 10px; +} + +.column-settings__hashtags { + .column-settings__row { + margin-bottom: 15px; + } - .column-settings__hashtag-select { + .column-select { &__control { @include search-input(); } + &__placeholder { + color: $dark-text-color; + padding-left: 2px; + font-size: 12px; + } + + &__value-container { + padding-left: 6px; + } + &__multi-value { background: lighten($ui-base-color, 8%); + + &__remove { + cursor: pointer; + + &:hover, + &:active, + &:focus { + background: lighten($ui-base-color, 12%); + color: lighten($darker-text-color, 4%); + } + } } &__multi-value__label, @@ -354,9 +381,42 @@ color: $darker-text-color; } - &__indicator-separator, + &__clear-indicator, &__dropdown-indicator { - display: none; + cursor: pointer; + transition: none; + color: $dark-text-color; + + &:hover, + &:active, + &:focus { + color: lighten($dark-text-color, 4%); + } + } + + &__indicator-separator { + background-color: lighten($ui-base-color, 8%); + } + + &__menu { + @include search-popout(); + padding: 0; + background: $ui-secondary-color; + } + + &__menu-list { + padding: 6px; + } + + &__option { + color: $inverted-text-color; + border-radius: 4px; + font-size: 14px; + + &--is-focused, + &--is-selected { + background: darken($ui-secondary-color, 10%); + } } } } diff --git a/app/javascript/flavours/glitch/styles/components/drawer.scss b/app/javascript/flavours/glitch/styles/components/drawer.scss index 2821deec7..f4931c36c 100644 --- a/app/javascript/flavours/glitch/styles/components/drawer.scss +++ b/app/javascript/flavours/glitch/styles/components/drawer.scss @@ -157,29 +157,7 @@ } .drawer--search--popout { - box-sizing: border-box; - margin-top: 10px; - border-radius: 4px; - padding: 10px 14px 14px 14px; - box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4); - color: $light-text-color; - background: $simple-background-color; - - h4 { - margin-bottom: 10px; - color: $light-text-color; - font-size: 13px; - font-weight: 500; - text-transform: uppercase; - } - - ul { margin-bottom: 10px } - li { padding: 4px 0 } - - em { - color: $inverted-text-color; - font-weight: 500; - } + @include search-popout(); } .drawer--account { diff --git a/app/javascript/flavours/glitch/styles/contrast/diff.scss b/app/javascript/flavours/glitch/styles/contrast/diff.scss index 7d8993a50..8429103b8 100644 --- a/app/javascript/flavours/glitch/styles/contrast/diff.scss +++ b/app/javascript/flavours/glitch/styles/contrast/diff.scss @@ -13,6 +13,10 @@ } } +.rich-formatting a, +.rich-formatting p a, +.rich-formatting li a, +.landing-page__short-description p a, .status__content a, .reply-indicator__content a { color: lighten($ui-highlight-color, 12%); diff --git a/app/javascript/mastodon/components/display_name.js b/app/javascript/mastodon/components/display_name.js index acddf77c5..32809778a 100644 --- a/app/javascript/mastodon/components/display_name.js +++ b/app/javascript/mastodon/components/display_name.js @@ -11,26 +11,36 @@ export default class DisplayName extends React.PureComponent { }; render () { - const { account, others, localDomain } = this.props; - const displayNameHtml = { __html: account.get('display_name_html') }; + const { others, localDomain } = this.props; - let suffix; + let displayName, suffix, account; if (others && others.size > 1) { - suffix = `+${others.size}`; + displayName = others.take(2).map(a => ).reduce((prev, cur) => [prev, ', ', cur]); + + if (others.size - 2 > 0) { + suffix = `+${others.size - 2}`; + } } else { + if (others) { + account = others.first(); + } else { + account = this.props.account; + } + let acct = account.get('acct'); if (acct.indexOf('@') === -1 && localDomain) { acct = `${acct}@${localDomain}`; } - suffix = @{acct}; + displayName = ; + suffix = @{acct}; } return ( - {suffix} + {displayName} {suffix} ); } diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 386404b57..3e98d374b 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -86,7 +86,7 @@ class Status extends ImmutablePureComponent { // Track height changes we know about to compensate scrolling componentDidMount () { - this.didShowCard = !this.props.muted && !this.props.hidden && this.props.status.get('card'); + this.didShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card'); } getSnapshotBeforeUpdate () { @@ -99,7 +99,7 @@ class Status extends ImmutablePureComponent { // Compensate height changes componentDidUpdate (prevProps, prevState, snapshot) { - const doShowCard = !this.props.muted && !this.props.hidden && this.props.status.get('card'); + const doShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card'); if (doShowCard && !this.didShowCard) { this.didShowCard = true; if (snapshot !== null && this.props.updateScrollBottom) { diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js index 038d7ee28..629cbc36a 100644 --- a/app/javascript/mastodon/features/compose/components/upload.js +++ b/app/javascript/mastodon/features/compose/components/upload.js @@ -108,9 +108,8 @@ class Upload extends ImmutablePureComponent {