mirror of
https://github.com/mastodon/mastodon.git
synced 2026-04-26 10:06:15 -05:00
Migrate to new theming infrastructure (#37612)
This commit is contained in:
parent
fb89198460
commit
75ba314e6b
|
|
@ -21,9 +21,7 @@ import { reducerWithInitialState } from '@/mastodon/reducers';
|
||||||
import { defaultMiddleware } from '@/mastodon/store/store';
|
import { defaultMiddleware } from '@/mastodon/store/store';
|
||||||
import { mockHandlers, unhandledRequestHandler } from '@/testing/api';
|
import { mockHandlers, unhandledRequestHandler } from '@/testing/api';
|
||||||
|
|
||||||
// If you want to run the dark theme during development,
|
import '../app/javascript/styles/application.scss';
|
||||||
// you can change the below to `/application.scss`
|
|
||||||
import '../app/javascript/styles/mastodon-light.scss';
|
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
import { modes } from './modes';
|
import { modes } from './modes';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -180,22 +180,11 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def color_scheme
|
def color_scheme
|
||||||
current = current_user&.setting_color_scheme
|
current_user&.setting_color_scheme || 'auto'
|
||||||
return current if current && current != 'auto'
|
|
||||||
|
|
||||||
return 'dark' if current_theme.include?('default') || current_theme.include?('contrast')
|
|
||||||
return 'light' if current_theme.include?('light')
|
|
||||||
|
|
||||||
'auto'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def contrast
|
def contrast
|
||||||
current = current_user&.setting_contrast
|
current_user&.setting_contrast || 'auto'
|
||||||
return current if current && current != 'auto'
|
|
||||||
|
|
||||||
return 'high' if current_theme.include?('contrast')
|
|
||||||
|
|
||||||
'auto'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def respond_with_error(code)
|
def respond_with_error(code)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@ module ThemeHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def theme_style_tags(theme)
|
def theme_style_tags(theme)
|
||||||
# TODO: get rid of that when we retire the themes and perform the settings migration
|
|
||||||
theme = 'default' if %w(mastodon-light contrast system).include?(theme)
|
|
||||||
|
|
||||||
vite_stylesheet_tag "themes/#{theme}", type: :virtual, media: 'all', crossorigin: 'anonymous'
|
vite_stylesheet_tag "themes/#{theme}", type: :virtual, media: 'all', crossorigin: 'anonymous'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
@use 'common';
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
@use 'common';
|
|
||||||
|
|
@ -16,6 +16,6 @@ class Themes
|
||||||
end
|
end
|
||||||
|
|
||||||
def names
|
def names
|
||||||
['system'] + @conf.keys
|
@conf.keys
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
= vite_client_tag
|
= vite_client_tag
|
||||||
= vite_react_refresh_tag
|
= vite_react_refresh_tag
|
||||||
= vite_polyfills_tag
|
= vite_polyfills_tag
|
||||||
= theme_style_tags 'system'
|
= theme_style_tags 'default'
|
||||||
= vite_preload_file_tag "mastodon/locales/#{I18n.locale}.json"
|
= vite_preload_file_tag "mastodon/locales/#{I18n.locale}.json"
|
||||||
= render_initial_state
|
= render_initial_state
|
||||||
= vite_typescript_tag 'embed.tsx', integrity: true, crossorigin: 'anonymous'
|
= vite_typescript_tag 'embed.tsx', integrity: true, crossorigin: 'anonymous'
|
||||||
|
|
|
||||||
|
|
@ -23,33 +23,34 @@
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||||
= ff.input :theme,
|
- if Themes.instance.names.size > 1
|
||||||
collection: Themes.instance.names,
|
= ff.input :theme,
|
||||||
hint: false,
|
collection: Themes.instance.names,
|
||||||
include_blank: false,
|
hint: false,
|
||||||
label_method: ->(theme) { I18n.t("themes.#{theme}", default: theme) },
|
include_blank: false,
|
||||||
label: I18n.t('simple_form.labels.defaults.setting_theme'),
|
label_method: ->(theme) { I18n.t("themes.#{theme}", default: theme) },
|
||||||
wrapper: :with_label,
|
label: I18n.t('simple_form.labels.defaults.setting_theme'),
|
||||||
required: false
|
wrapper: :with_label,
|
||||||
- if Mastodon::Feature.new_theme_options_enabled?
|
required: false
|
||||||
.input.horizontal-options
|
|
||||||
= ff.input :'web.color_scheme',
|
.input.horizontal-options
|
||||||
as: :radio_buttons,
|
= ff.input :'web.color_scheme',
|
||||||
collection: %w(auto light dark),
|
as: :radio_buttons,
|
||||||
include_blank: false,
|
collection: %w(auto light dark),
|
||||||
label: I18n.t('simple_form.labels.defaults.setting_color_scheme'),
|
include_blank: false,
|
||||||
label_method: ->(contrast) { I18n.t("color_scheme.#{contrast}", default: contrast) },
|
label: I18n.t('simple_form.labels.defaults.setting_color_scheme'),
|
||||||
wrapper: :with_label,
|
label_method: ->(contrast) { I18n.t("color_scheme.#{contrast}", default: contrast) },
|
||||||
required: false
|
wrapper: :with_label,
|
||||||
.input.horizontal-options
|
required: false
|
||||||
= ff.input :'web.contrast',
|
.input.horizontal-options
|
||||||
as: :radio_buttons,
|
= ff.input :'web.contrast',
|
||||||
collection: %w(auto high),
|
as: :radio_buttons,
|
||||||
include_blank: false,
|
collection: %w(auto high),
|
||||||
label: I18n.t('simple_form.labels.defaults.setting_contrast'),
|
include_blank: false,
|
||||||
label_method: ->(contrast) { I18n.t("contrast.#{contrast}", default: contrast) },
|
label: I18n.t('simple_form.labels.defaults.setting_contrast'),
|
||||||
wrapper: :with_label,
|
label_method: ->(contrast) { I18n.t("contrast.#{contrast}", default: contrast) },
|
||||||
required: false
|
wrapper: :with_label,
|
||||||
|
required: false
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||||
|
|
|
||||||
|
|
@ -2022,10 +2022,7 @@ en:
|
||||||
review_link: Review terms of service
|
review_link: Review terms of service
|
||||||
title: The terms of service of %{domain} are changing
|
title: The terms of service of %{domain} are changing
|
||||||
themes:
|
themes:
|
||||||
contrast: Mastodon (High contrast)
|
default: Mastodon
|
||||||
default: Mastodon (Dark)
|
|
||||||
mastodon-light: Mastodon (Light)
|
|
||||||
system: Automatic (use system theme)
|
|
||||||
time:
|
time:
|
||||||
formats:
|
formats:
|
||||||
default: "%b %d, %Y, %H:%M"
|
default: "%b %d, %Y, %H:%M"
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ defaults: &defaults
|
||||||
show_staff_badge: true
|
show_staff_badge: true
|
||||||
preview_sensitive_media: false
|
preview_sensitive_media: false
|
||||||
noindex: false
|
noindex: false
|
||||||
theme: 'system'
|
theme: 'default'
|
||||||
trends: true
|
trends: true
|
||||||
trendable_by_default: false
|
trendable_by_default: false
|
||||||
disallowed_hashtags: # space separated string or list of hashtags without the hash
|
disallowed_hashtags: # space separated string or list of hashtags without the hash
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1 @@
|
||||||
default: styles/application.scss
|
default: styles/application.scss
|
||||||
contrast: styles/contrast.scss
|
|
||||||
mastodon-light: styles/mastodon-light.scss
|
|
||||||
|
|
|
||||||
22
db/migrate/20260209142402_migrate_default_theme_setting.rb
Normal file
22
db/migrate/20260209142402_migrate_default_theme_setting.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class MigrateDefaultThemeSetting < ActiveRecord::Migration[8.0]
|
||||||
|
class Setting < ApplicationRecord; end
|
||||||
|
|
||||||
|
def up
|
||||||
|
Setting.reset_column_information
|
||||||
|
|
||||||
|
setting = Setting.find_by(var: 'theme')
|
||||||
|
return unless setting.present? && setting.attributes['value'].present? && %w(mastodon-light contrast system).include?(setting.attributes['value'])
|
||||||
|
|
||||||
|
Setting.upsert(
|
||||||
|
{
|
||||||
|
var: 'theme',
|
||||||
|
value: "--- default\n",
|
||||||
|
},
|
||||||
|
unique_by: index_exists?(:settings, [:thing_type, :thing_id, :var]) ? [:thing_type, :thing_id, :var] : :var
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down; end
|
||||||
|
end
|
||||||
31
db/migrate/20260209143308_migrate_user_theme.rb
Normal file
31
db/migrate/20260209143308_migrate_user_theme.rb
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class MigrateUserTheme < ActiveRecord::Migration[8.0]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
# Dummy classes, to make migration possible across version changes
|
||||||
|
class User < ApplicationRecord; end
|
||||||
|
|
||||||
|
def up
|
||||||
|
User.where.not(settings: nil).find_each do |user|
|
||||||
|
settings = Oj.load(user.attributes_before_type_cast['settings'])
|
||||||
|
next if settings.nil? || settings['theme'].blank? || %w(system default mastodon-light contrast).exclude?(settings['theme'])
|
||||||
|
|
||||||
|
case settings['theme']
|
||||||
|
when 'default'
|
||||||
|
settings['web.color_scheme'] = 'dark'
|
||||||
|
settings['web.contrast'] = 'auto'
|
||||||
|
when 'contrast'
|
||||||
|
settings['web.color_scheme'] = 'dark'
|
||||||
|
settings['web.contrast'] = 'high'
|
||||||
|
when 'mastodon-light'
|
||||||
|
settings['web.color_scheme'] = 'light'
|
||||||
|
settings['web.contrast'] = 'auto'
|
||||||
|
end
|
||||||
|
|
||||||
|
settings['theme'] = 'default'
|
||||||
|
|
||||||
|
user.update_column('settings', Oj.dump(settings))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.0].define(version: 2026_01_27_141820) do
|
ActiveRecord::Schema[8.0].define(version: 2026_02_09_143308) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pg_catalog.plpgsql"
|
enable_extension "pg_catalog.plpgsql"
|
||||||
|
|
||||||
|
|
@ -1127,6 +1127,7 @@ ActiveRecord::Schema[8.0].define(version: 2026_01_27_141820) do
|
||||||
t.string "poll_options", array: true
|
t.string "poll_options", array: true
|
||||||
t.boolean "sensitive"
|
t.boolean "sensitive"
|
||||||
t.bigint "quote_id"
|
t.bigint "quote_id"
|
||||||
|
t.string "content_type"
|
||||||
t.index ["account_id"], name: "index_status_edits_on_account_id"
|
t.index ["account_id"], name: "index_status_edits_on_account_id"
|
||||||
t.index ["status_id"], name: "index_status_edits_on_status_id"
|
t.index ["status_id"], name: "index_status_edits_on_status_id"
|
||||||
end
|
end
|
||||||
|
|
@ -1189,6 +1190,8 @@ ActiveRecord::Schema[8.0].define(version: 2026_01_27_141820) do
|
||||||
t.bigint "ordered_media_attachment_ids", array: true
|
t.bigint "ordered_media_attachment_ids", array: true
|
||||||
t.datetime "fetched_replies_at"
|
t.datetime "fetched_replies_at"
|
||||||
t.integer "quote_approval_policy", default: 0, null: false
|
t.integer "quote_approval_policy", default: 0, null: false
|
||||||
|
t.boolean "local_only"
|
||||||
|
t.string "content_type"
|
||||||
t.index ["account_id", "id", "visibility", "updated_at"], name: "index_statuses_20190820", order: { id: :desc }, where: "(deleted_at IS NULL)"
|
t.index ["account_id", "id", "visibility", "updated_at"], name: "index_statuses_20190820", order: { id: :desc }, where: "(deleted_at IS NULL)"
|
||||||
t.index ["account_id"], name: "index_statuses_on_account_id"
|
t.index ["account_id"], name: "index_statuses_on_account_id"
|
||||||
t.index ["conversation_id"], name: "index_statuses_on_conversation_id"
|
t.index ["conversation_id"], name: "index_statuses_on_conversation_id"
|
||||||
|
|
|
||||||
|
|
@ -97,24 +97,6 @@ RSpec.describe ApplicationController do
|
||||||
|
|
||||||
expect(controller.view_context.current_theme).to eq 'contrast'
|
expect(controller.view_context.current_theme).to eq 'contrast'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns instances\'s default theme when user didn\'t set theme' do
|
|
||||||
current_user = Fabricate(:user)
|
|
||||||
current_user.settings.update(theme: 'contrast', noindex: false)
|
|
||||||
current_user.save
|
|
||||||
sign_in current_user
|
|
||||||
|
|
||||||
expect(controller.view_context.current_theme).to eq 'contrast'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns user\'s theme when it is set' do
|
|
||||||
current_user = Fabricate(:user)
|
|
||||||
current_user.settings.update(theme: 'mastodon-light')
|
|
||||||
current_user.save
|
|
||||||
sign_in current_user
|
|
||||||
|
|
||||||
expect(controller.view_context.current_theme).to eq 'mastodon-light'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with ActionController::RoutingError' do
|
context 'with ActionController::RoutingError' do
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,6 @@ RSpec.describe ThemeHelper do
|
||||||
describe 'theme_style_tags' do
|
describe 'theme_style_tags' do
|
||||||
let(:result) { helper.theme_style_tags(theme) }
|
let(:result) { helper.theme_style_tags(theme) }
|
||||||
|
|
||||||
context 'when using "system" theme' do
|
|
||||||
let(:theme) { 'system' }
|
|
||||||
|
|
||||||
it 'returns the default theme' do
|
|
||||||
expect(html_links.first.attributes.symbolize_keys)
|
|
||||||
.to include(
|
|
||||||
href: have_attributes(value: match(/default/))
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when using "default" theme' do
|
context 'when using "default" theme' do
|
||||||
let(:theme) { 'default' }
|
let(:theme) { 'default' }
|
||||||
|
|
||||||
|
|
@ -27,17 +16,6 @@ RSpec.describe ThemeHelper do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when using other theme' do
|
|
||||||
let(:theme) { 'contrast' }
|
|
||||||
|
|
||||||
it 'returns the theme stylesheet without color scheme information' do
|
|
||||||
expect(html_links.first.attributes.symbolize_keys)
|
|
||||||
.to include(
|
|
||||||
href: have_attributes(value: match(/default/))
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'theme_color_tags' do
|
describe 'theme_color_tags' do
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,13 @@ RSpec.describe 'Settings preferences appearance page' do
|
||||||
expect(page)
|
expect(page)
|
||||||
.to have_private_cache_control
|
.to have_private_cache_control
|
||||||
|
|
||||||
select 'contrast', from: theme_selection_field
|
|
||||||
check confirm_reblog_field
|
check confirm_reblog_field
|
||||||
uncheck confirm_delete_field
|
uncheck confirm_delete_field
|
||||||
|
|
||||||
check advanced_layout_field
|
check advanced_layout_field
|
||||||
|
|
||||||
expect { save_changes }
|
expect { save_changes }
|
||||||
.to change { user.reload.settings.theme }.to('contrast')
|
.to change { user.reload.settings['web.reblog_modal'] }.to(true)
|
||||||
.and change { user.reload.settings['web.reblog_modal'] }.to(true)
|
|
||||||
.and change { user.reload.settings['web.delete_modal'] }.to(false)
|
.and change { user.reload.settings['web.delete_modal'] }.to(false)
|
||||||
.and(change { user.reload.settings['web.advanced_layout'] }.to(true))
|
.and(change { user.reload.settings['web.advanced_layout'] }.to(true))
|
||||||
expect(page)
|
expect(page)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user