Migrate to new theming infrastructure (#37612)

pull/37792/head
Claire 2 weeks ago committed by GitHub
parent fb89198460
commit 75ba314e6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -21,9 +21,7 @@ import { reducerWithInitialState } from '@/mastodon/reducers';
import { defaultMiddleware } from '@/mastodon/store/store';
import { mockHandlers, unhandledRequestHandler } from '@/testing/api';
// If you want to run the dark theme during development,
// you can change the below to `/application.scss`
import '../app/javascript/styles/mastodon-light.scss';
import '../app/javascript/styles/application.scss';
import './styles.css';
import { modes } from './modes';

@ -180,22 +180,11 @@ class ApplicationController < ActionController::Base
end
def color_scheme
current = current_user&.setting_color_scheme
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'
current_user&.setting_color_scheme || 'auto'
end
def contrast
current = current_user&.setting_contrast
return current if current && current != 'auto'
return 'high' if current_theme.include?('contrast')
'auto'
current_user&.setting_contrast || 'auto'
end
def respond_with_error(code)

@ -18,9 +18,6 @@ module ThemeHelper
end
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'
end

@ -16,6 +16,6 @@ class Themes
end
def names
['system'] + @conf.keys
@conf.keys
end
end

@ -15,7 +15,7 @@
= vite_client_tag
= vite_react_refresh_tag
= vite_polyfills_tag
= theme_style_tags 'system'
= theme_style_tags 'default'
= vite_preload_file_tag "mastodon/locales/#{I18n.locale}.json"
= render_initial_state
= vite_typescript_tag 'embed.tsx', integrity: true, crossorigin: 'anonymous'

@ -23,33 +23,34 @@
.fields-group
= f.simple_fields_for :settings, current_user.settings do |ff|
= ff.input :theme,
collection: Themes.instance.names,
hint: false,
include_blank: false,
label_method: ->(theme) { I18n.t("themes.#{theme}", default: theme) },
label: I18n.t('simple_form.labels.defaults.setting_theme'),
wrapper: :with_label,
required: false
- if Mastodon::Feature.new_theme_options_enabled?
.input.horizontal-options
= ff.input :'web.color_scheme',
as: :radio_buttons,
collection: %w(auto light dark),
include_blank: false,
label: I18n.t('simple_form.labels.defaults.setting_color_scheme'),
label_method: ->(contrast) { I18n.t("color_scheme.#{contrast}", default: contrast) },
wrapper: :with_label,
required: false
.input.horizontal-options
= ff.input :'web.contrast',
as: :radio_buttons,
collection: %w(auto high),
include_blank: false,
label: I18n.t('simple_form.labels.defaults.setting_contrast'),
label_method: ->(contrast) { I18n.t("contrast.#{contrast}", default: contrast) },
wrapper: :with_label,
required: false
- if Themes.instance.names.size > 1
= ff.input :theme,
collection: Themes.instance.names,
hint: false,
include_blank: false,
label_method: ->(theme) { I18n.t("themes.#{theme}", default: theme) },
label: I18n.t('simple_form.labels.defaults.setting_theme'),
wrapper: :with_label,
required: false
.input.horizontal-options
= ff.input :'web.color_scheme',
as: :radio_buttons,
collection: %w(auto light dark),
include_blank: false,
label: I18n.t('simple_form.labels.defaults.setting_color_scheme'),
label_method: ->(contrast) { I18n.t("color_scheme.#{contrast}", default: contrast) },
wrapper: :with_label,
required: false
.input.horizontal-options
= ff.input :'web.contrast',
as: :radio_buttons,
collection: %w(auto high),
include_blank: false,
label: I18n.t('simple_form.labels.defaults.setting_contrast'),
label_method: ->(contrast) { I18n.t("contrast.#{contrast}", default: contrast) },
wrapper: :with_label,
required: false
.fields-group
= f.simple_fields_for :settings, current_user.settings do |ff|

@ -2022,10 +2022,7 @@ en:
review_link: Review terms of service
title: The terms of service of %{domain} are changing
themes:
contrast: Mastodon (High contrast)
default: Mastodon (Dark)
mastodon-light: Mastodon (Light)
system: Automatic (use system theme)
default: Mastodon
time:
formats:
default: "%b %d, %Y, %H:%M"

@ -19,7 +19,7 @@ defaults: &defaults
show_staff_badge: true
preview_sensitive_media: false
noindex: false
theme: 'system'
theme: 'default'
trends: true
trendable_by_default: false
disallowed_hashtags: # space separated string or list of hashtags without the hash

@ -1,3 +1 @@
default: styles/application.scss
contrast: styles/contrast.scss
mastodon-light: styles/mastodon-light.scss

@ -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

@ -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.
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
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.boolean "sensitive"
t.bigint "quote_id"
t.string "content_type"
t.index ["account_id"], name: "index_status_edits_on_account_id"
t.index ["status_id"], name: "index_status_edits_on_status_id"
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.datetime "fetched_replies_at"
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"], name: "index_statuses_on_account_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'
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
context 'with ActionController::RoutingError' do

@ -6,17 +6,6 @@ RSpec.describe ThemeHelper do
describe 'theme_style_tags' do
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
let(:theme) { 'default' }
@ -27,17 +16,6 @@ RSpec.describe ThemeHelper do
)
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
describe 'theme_color_tags' do

@ -13,15 +13,13 @@ RSpec.describe 'Settings preferences appearance page' do
expect(page)
.to have_private_cache_control
select 'contrast', from: theme_selection_field
check confirm_reblog_field
uncheck confirm_delete_field
check advanced_layout_field
expect { save_changes }
.to change { user.reload.settings.theme }.to('contrast')
.and change { user.reload.settings['web.reblog_modal'] }.to(true)
.to 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.advanced_layout'] }.to(true))
expect(page)

Loading…
Cancel
Save