diff --git a/app/javascript/flavours/glitch/components/column_header.js b/app/javascript/flavours/glitch/components/column_header.js
index ccd0714f1b..500612093b 100644
--- a/app/javascript/flavours/glitch/components/column_header.js
+++ b/app/javascript/flavours/glitch/components/column_header.js
@@ -124,8 +124,8 @@ class ColumnHeader extends React.PureComponent {
moveButtons = (
-
-
+
+
);
} else if (multiColumn && this.props.onPin) {
@@ -146,8 +146,8 @@ class ColumnHeader extends React.PureComponent {
];
if (multiColumn) {
- collapsedContent.push(moveButtons);
collapsedContent.push(pinButton);
+ collapsedContent.push(moveButtons);
}
if (children || (multiColumn && this.props.onPin)) {
diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss
index ad17ed4b0a..04d9b41688 100644
--- a/app/javascript/flavours/glitch/styles/components/columns.scss
+++ b/app/javascript/flavours/glitch/styles/components/columns.scss
@@ -437,12 +437,17 @@
}
.column-header__setting-btn {
- &:hover {
+ &:hover,
+ &:focus {
color: $darker-text-color;
text-decoration: underline;
}
}
+.column-header__collapsible__extra + .column-header__setting-btn {
+ padding-top: 5px;
+}
+
.column-header__permission-btn {
display: inline;
font-weight: inherit;
@@ -453,10 +458,15 @@
float: right;
.column-header__setting-btn {
- padding: 0 10px;
+ padding: 5px;
+
+ &:first-child {
+ padding-right: 7px;
+ }
&:last-child {
- padding-right: 0;
+ padding-left: 7px;
+ margin-left: 5px;
}
}
}
diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss
index 04bd8805a5..2281a4bb32 100644
--- a/app/javascript/flavours/glitch/styles/components/index.scss
+++ b/app/javascript/flavours/glitch/styles/components/index.scss
@@ -829,7 +829,7 @@
transition: background-color 0.2s ease;
}
-.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
+.react-toggle:is(:hover, :focus-within):not(.react-toggle--disabled) .react-toggle-track {
background-color: darken($ui-base-color, 10%);
}
@@ -837,7 +837,7 @@
background-color: $ui-highlight-color;
}
-.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
+.react-toggle--checked:is(:hover, :focus-within):not(.react-toggle--disabled) .react-toggle-track {
background-color: lighten($ui-highlight-color, 10%);
}
diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss
index f6a90d271d..61e95ad243 100644
--- a/app/javascript/flavours/glitch/styles/rtl.scss
+++ b/app/javascript/flavours/glitch/styles/rtl.scss
@@ -112,6 +112,20 @@ body.rtl {
.column-header__setting-arrows {
float: left;
+
+ .column-header__setting-btn {
+ &:first-child {
+ padding-left: 7px;
+ padding-right: 5px;
+ }
+
+ &:last-child {
+ padding-right: 7px;
+ padding-left: 5px;
+ margin-right: 5px;
+ margin-left: 0;
+ }
+ }
}
.setting-toggle__label {
@@ -428,11 +442,6 @@ body.rtl {
margin-left: 5px;
}
- .column-header__setting-arrows .column-header__setting-btn:last-child {
- padding-left: 0;
- padding-right: 10px;
- }
-
.simple_form .input.radio_buttons .radio > label input {
left: auto;
right: 0;
diff --git a/app/javascript/mastodon/components/column_header.js b/app/javascript/mastodon/components/column_header.js
index 236e922969..cbbc490a83 100644
--- a/app/javascript/mastodon/components/column_header.js
+++ b/app/javascript/mastodon/components/column_header.js
@@ -119,8 +119,8 @@ class ColumnHeader extends React.PureComponent {
moveButtons = (
-
-
+
+
);
} else if (multiColumn && this.props.onPin) {
@@ -141,8 +141,8 @@ class ColumnHeader extends React.PureComponent {
];
if (multiColumn) {
- collapsedContent.push(moveButtons);
collapsedContent.push(pinButton);
+ collapsedContent.push(moveButtons);
}
if (children || (multiColumn && this.props.onPin)) {
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 30ac804ea6..12bc472f5f 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2822,7 +2822,7 @@ a.account__display-name {
transition: background-color 0.2s ease;
}
-.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
+.react-toggle:is(:hover, :focus-within):not(.react-toggle--disabled) .react-toggle-track {
background-color: darken($ui-base-color, 10%);
}
@@ -2830,7 +2830,7 @@ a.account__display-name {
background-color: $ui-highlight-color;
}
-.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
+.react-toggle--checked:is(:hover, :focus-within):not(.react-toggle--disabled) .react-toggle-track {
background-color: lighten($ui-highlight-color, 10%);
}
@@ -3548,12 +3548,17 @@ a.status-card.compact:hover {
}
.column-header__setting-btn {
- &:hover {
+ &:hover,
+ &:focus {
color: $darker-text-color;
text-decoration: underline;
}
}
+.column-header__collapsible__extra + .column-header__setting-btn {
+ padding-top: 5px;
+}
+
.column-header__permission-btn {
display: inline;
font-weight: inherit;
@@ -3564,10 +3569,15 @@ a.status-card.compact:hover {
float: right;
.column-header__setting-btn {
- padding: 0 10px;
+ padding: 5px;
+
+ &:first-child {
+ padding-right: 7px;
+ }
&:last-child {
- padding-right: 0;
+ padding-left: 7px;
+ margin-left: 5px;
}
}
}
diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss
index baacf46b9f..ea7bb5113c 100644
--- a/app/javascript/styles/mastodon/rtl.scss
+++ b/app/javascript/styles/mastodon/rtl.scss
@@ -126,6 +126,20 @@ body.rtl {
.column-header__setting-arrows {
float: left;
+
+ .column-header__setting-btn {
+ &:first-child {
+ padding-left: 7px;
+ padding-right: 5px;
+ }
+
+ &:last-child {
+ padding-right: 7px;
+ padding-left: 5px;
+ margin-right: 5px;
+ margin-left: 0;
+ }
+ }
}
.setting-toggle__label {
@@ -451,11 +465,6 @@ body.rtl {
margin-left: 5px;
}
- .column-header__setting-arrows .column-header__setting-btn:last-child {
- padding-left: 0;
- padding-right: 10px;
- }
-
.simple_form .input.radio_buttons .radio > label input {
left: auto;
right: 0;
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index b57600356c..a80087fa3e 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -167,12 +167,11 @@ class MediaAttachment < ApplicationRecord
processors: ->(f) { file_processors f },
convert_options: GLOBAL_CONVERT_OPTIONS
- before_file_post_process :set_type_and_extension
- before_file_post_process :check_video_dimensions
+ before_file_validate :set_type_and_extension
+ before_file_validate :check_video_dimensions
validates_attachment_content_type :file, content_type: IMAGE_MIME_TYPES + VIDEO_MIME_TYPES + AUDIO_MIME_TYPES
- validates_attachment_size :file, less_than: IMAGE_LIMIT, unless: :larger_media_format?
- validates_attachment_size :file, less_than: VIDEO_LIMIT, if: :larger_media_format?
+ validates_attachment_size :file, less_than: ->(m) { m.larger_media_format? ? VIDEO_LIMIT : IMAGE_LIMIT }
remotable_attachment :file, VIDEO_LIMIT, suppress_errors: false, download_on_assign: false, attribute_name: :remote_url
has_attached_file :thumbnail,
diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb
index edab67d476..5dbb3d2060 100644
--- a/spec/models/media_attachment_spec.rb
+++ b/spec/models/media_attachment_spec.rb
@@ -181,4 +181,32 @@ RSpec.describe MediaAttachment, type: :model do
expect(media.description.size).to be <= 1_500
end
end
+
+ describe 'size limit validation' do
+ it 'rejects video files that are too large' do
+ stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes
+ stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte
+ expect { MediaAttachment.create!(account: Fabricate(:account), file: attachment_fixture('attachment.webm')) }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it 'accepts video files that are small enough' do
+ stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte
+ stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes
+ media = MediaAttachment.create!(account: Fabricate(:account), file: attachment_fixture('attachment.webm'))
+ expect(media.valid?).to be true
+ end
+
+ it 'rejects image files that are too large' do
+ stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte
+ stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes
+ expect { MediaAttachment.create!(account: Fabricate(:account), file: attachment_fixture('attachment.jpg')) }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ it 'accepts image files that are small enough' do
+ stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes
+ stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte
+ media = MediaAttachment.create!(account: Fabricate(:account), file: attachment_fixture('attachment.jpg'))
+ expect(media.valid?).to be true
+ end
+ end
end