diff --git a/.gitmodules b/.gitmodules
index 35b0cd787d2..e69de29bb2d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "app/javascript/themes/mastodon-go"]
- path = app/javascript/themes/mastodon-go
- url = https://github.com/marrus-sh/mastodon-go
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
index 47690e81eb9..8785df14ed1 100644
--- a/app/controllers/about_controller.rb
+++ b/app/controllers/about_controller.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class AboutController < ApplicationController
+ before_action :set_pack
before_action :set_body_classes
before_action :set_instance_presenter, only: [:show, :more, :terms]
@@ -21,6 +22,10 @@ class AboutController < ApplicationController
helper_method :new_user
+ def set_pack
+ use_pack action_name == 'show' ? 'about' : 'common'
+ end
+
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 75915b33712..309cb65daa6 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -7,6 +7,7 @@ class AccountsController < ApplicationController
def show
respond_to do |format|
format.html do
+ use_pack 'public'
@pinned_statuses = []
if current_account && @account.blocking?(current_account)
diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb
index 7fb69d5789e..fc299f74c5f 100644
--- a/app/controllers/admin/base_controller.rb
+++ b/app/controllers/admin/base_controller.rb
@@ -5,8 +5,13 @@ module Admin
include Authorization
include AccountableConcern
- before_action :require_staff!
-
layout 'admin'
+
+ before_action :require_staff!
+ before_action :set_pack
+
+ def set_pack
+ use_pack 'admin'
+ end
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index f5dbe837e4f..d116c4767eb 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -12,8 +12,8 @@ class ApplicationController < ActionController::Base
helper_method :current_account
helper_method :current_session
- helper_method :current_theme
- helper_method :theme_data
+ helper_method :current_flavour
+ helper_method :current_skin
helper_method :single_user_mode?
rescue_from ActionController::RoutingError, with: :not_found
@@ -54,6 +54,73 @@ class ApplicationController < ActionController::Base
new_user_session_path
end
+ def pack(data, pack_name, skin = 'default')
+ return nil unless pack?(data, pack_name)
+ pack_data = {
+ common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common'),
+ flavour: data['name'],
+ pack: pack_name,
+ preload: nil,
+ skin: nil,
+ }
+ if data['pack'][pack_name].is_a?(Hash)
+ pack_data[:common] = nil if data['pack'][pack_name]['use_common'] == false
+ pack_data[:pack] = nil unless data['pack'][pack_name]['filename']
+ if data['pack'][pack_name]['preload']
+ pack_data[:preload] = [data['pack'][pack_name]['preload']] if data['pack'][pack_name]['preload'].is_a?(String)
+ pack_data[:preload] = data['pack'][pack_name]['preload'] if data['pack'][pack_name]['preload'].is_a?(Array)
+ end
+ if skin != 'default' && data['skin'][skin]
+ pack_data[:skin] = skin if data['skin'][skin].include?(pack_name)
+ else # default skin
+ pack_data[:skin] = 'default' if data['pack'][pack_name]['stylesheet']
+ end
+ end
+ pack_data
+ end
+
+ def pack?(data, pack_name)
+ if data['pack'].is_a?(Hash) && data['pack'].key?(pack_name)
+ return true if data['pack'][pack_name].is_a?(String) || data['pack'][pack_name].is_a?(Hash)
+ end
+ false
+ end
+
+ def nil_pack(data, pack_name, skin = 'default')
+ {
+ common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common', skin),
+ flavour: data['name'],
+ pack: nil,
+ preload: nil,
+ skin: nil,
+ }
+ end
+
+ def resolve_pack(data, pack_name, skin = 'default')
+ result = pack(data, pack_name, skin)
+ unless result
+ if data['name'] && data.key?('fallback')
+ if data['fallback'].nil?
+ return nil_pack(data, pack_name, skin)
+ elsif data['fallback'].is_a?(String) && Themes.instance.flavour(data['fallback'])
+ return resolve_pack(Themes.instance.flavour(data['fallback']), pack_name, skin)
+ elsif data['fallback'].is_a?(Array)
+ data['fallback'].each do |fallback|
+ return resolve_pack(Themes.instance.flavour(fallback), pack_name, skin) if Themes.instance.flavour(fallback)
+ end
+ end
+ return nil_pack(data, pack_name, skin)
+ end
+ return data.key?('name') && data['name'] != Setting.default_settings['flavour'] ? resolve_pack(Themes.instance.flavour(Setting.default_settings['flavour']), pack_name, skin) : nil_pack(data, pack_name, skin)
+ end
+ result
+ end
+
+ def use_pack(pack_name)
+ @core = resolve_pack(Themes.instance.core, pack_name)
+ @theme = resolve_pack(Themes.instance.flavour(current_flavour), pack_name, current_skin)
+ end
+
protected
def forbidden
@@ -84,13 +151,14 @@ class ApplicationController < ActionController::Base
@current_session ||= SessionActivation.find_by(session_id: cookies.signed['_session_id'])
end
- def current_theme
- return Setting.default_settings['theme'] unless Themes.instance.names.include? current_user&.setting_theme
- current_user.setting_theme
+ def current_flavour
+ return Setting.default_settings['flavour'] unless Themes.instance.flavours.include? current_user&.setting_flavour
+ current_user.setting_flavour
end
- def theme_data
- Themes.instance.get(current_theme)
+ def current_skin
+ return 'default' unless Themes.instance.skins_for(current_flavour).include? current_user&.setting_skin
+ current_user.setting_skin
end
def cache_collection(raw, klass)
diff --git a/app/controllers/auth/confirmations_controller.rb b/app/controllers/auth/confirmations_controller.rb
index d5e8e58ede3..5ffa1c9a307 100644
--- a/app/controllers/auth/confirmations_controller.rb
+++ b/app/controllers/auth/confirmations_controller.rb
@@ -2,10 +2,17 @@
class Auth::ConfirmationsController < Devise::ConfirmationsController
layout 'auth'
+ before_action :set_pack
def show
super do |user|
BootstrapTimelineWorker.perform_async(user.account_id) if user.errors.empty?
end
end
+
+ private
+
+ def set_pack
+ use_pack 'auth'
+ end
end
diff --git a/app/controllers/auth/passwords_controller.rb b/app/controllers/auth/passwords_controller.rb
index 171b997dc48..e0400aa3df8 100644
--- a/app/controllers/auth/passwords_controller.rb
+++ b/app/controllers/auth/passwords_controller.rb
@@ -2,6 +2,7 @@
class Auth::PasswordsController < Devise::PasswordsController
before_action :check_validity_of_reset_password_token, only: :edit
+ before_action :set_pack
layout 'auth'
@@ -17,4 +18,8 @@ class Auth::PasswordsController < Devise::PasswordsController
def reset_password_token_is_valid?
resource_class.with_reset_password_token(params[:reset_password_token]).present?
end
+
+ def set_pack
+ use_pack 'auth'
+ end
end
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index da0b6512f28..f4247fd95ea 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -5,6 +5,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
before_action :check_enabled_registrations, only: [:new, :create]
before_action :configure_sign_up_params, only: [:create]
+ before_action :set_pack
before_action :set_sessions, only: [:edit, :update]
before_action :set_instance_presenter, only: [:new, :create, :update]
@@ -55,6 +56,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
private
+ def set_pack
+ use_pack %w(edit update).include?(action_name) ? 'admin' : 'auth'
+ end
+
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb
index a5acb6c36fa..72d54410223 100644
--- a/app/controllers/auth/sessions_controller.rb
+++ b/app/controllers/auth/sessions_controller.rb
@@ -9,6 +9,7 @@ class Auth::SessionsController < Devise::SessionsController
skip_before_action :check_suspension, only: [:destroy]
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
before_action :set_instance_presenter, only: [:new]
+ before_action :set_pack
def create
super do |resource|
@@ -85,6 +86,10 @@ class Auth::SessionsController < Devise::SessionsController
private
+ def set_pack
+ use_pack 'auth'
+ end
+
def set_instance_presenter
@instance_presenter = InstancePresenter.new
end
diff --git a/app/controllers/authorize_follows_controller.rb b/app/controllers/authorize_follows_controller.rb
index 78b56418364..2d29bd37940 100644
--- a/app/controllers/authorize_follows_controller.rb
+++ b/app/controllers/authorize_follows_controller.rb
@@ -4,6 +4,7 @@ class AuthorizeFollowsController < ApplicationController
layout 'modal'
before_action :authenticate_user!
+ before_action :set_pack
def show
@account = located_account || render(:error)
@@ -23,6 +24,10 @@ class AuthorizeFollowsController < ApplicationController
private
+ def set_pack
+ use_pack 'modal'
+ end
+
def follow_attempt
FollowService.new.call(current_account, acct_without_prefix)
end
diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb
index 399e79665e7..080cbde1146 100644
--- a/app/controllers/follower_accounts_controller.rb
+++ b/app/controllers/follower_accounts_controller.rb
@@ -7,7 +7,9 @@ class FollowerAccountsController < ApplicationController
@follows = Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
respond_to do |format|
- format.html
+ format.html do
+ use_pack 'public'
+ end
format.json do
render json: collection_presenter,
diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb
index 1e73d4bd408..74e83ad814e 100644
--- a/app/controllers/following_accounts_controller.rb
+++ b/app/controllers/following_accounts_controller.rb
@@ -7,7 +7,9 @@ class FollowingAccountsController < ApplicationController
@follows = Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
respond_to do |format|
- format.html
+ format.html do
+ use_pack 'public'
+ end
format.json do
render json: collection_presenter,
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 21dde20ce40..7437a647e18 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -2,6 +2,7 @@
class HomeController < ApplicationController
before_action :authenticate_user!
+ before_action :set_pack
before_action :set_initial_state_json
def index
@@ -37,6 +38,10 @@ class HomeController < ApplicationController
redirect_to(default_redirect_path)
end
+ def set_pack
+ use_pack 'home'
+ end
+
def set_initial_state_json
serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer)
@initial_state_json = serializable_resource.to_json
diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb
index 48b026aa5a0..e6f37988612 100644
--- a/app/controllers/remote_follow_controller.rb
+++ b/app/controllers/remote_follow_controller.rb
@@ -4,6 +4,7 @@ class RemoteFollowController < ApplicationController
layout 'modal'
before_action :set_account
+ before_action :set_pack
before_action :gone, if: :suspended_account?
def new
@@ -31,6 +32,10 @@ class RemoteFollowController < ApplicationController
{ acct: session[:remote_follow] }
end
+ def set_pack
+ use_pack 'modal'
+ end
+
def set_account
@account = Account.find_local!(params[:account_username])
end
diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb
index 8fc9a0fa999..35a6f7f9e75 100644
--- a/app/controllers/settings/applications_controller.rb
+++ b/app/controllers/settings/applications_controller.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-class Settings::ApplicationsController < ApplicationController
- layout 'admin'
+class Settings::ApplicationsController < Settings::BaseController
- before_action :authenticate_user!
before_action :set_application, only: [:show, :update, :destroy, :regenerate]
before_action :prepare_scopes, only: [:create, :update]
diff --git a/app/controllers/settings/base_controller.rb b/app/controllers/settings/base_controller.rb
new file mode 100644
index 00000000000..7322d461be5
--- /dev/null
+++ b/app/controllers/settings/base_controller.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class Settings::BaseController < ApplicationController
+ layout 'admin'
+
+ before_action :authenticate_user!
+ before_action :set_pack
+
+ def set_pack
+ use_pack 'settings'
+ end
+end
diff --git a/app/controllers/settings/deletes_controller.rb b/app/controllers/settings/deletes_controller.rb
index 80002b995e5..4c112147114 100644
--- a/app/controllers/settings/deletes_controller.rb
+++ b/app/controllers/settings/deletes_controller.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
-class Settings::DeletesController < ApplicationController
- layout 'admin'
+class Settings::DeletesController < Settings::BaseController
- before_action :check_enabled_deletion
- before_action :authenticate_user!
+ prepend_before_action :check_enabled_deletion
def show
@confirmation = Form::DeleteConfirmation.new
diff --git a/app/controllers/settings/exports_controller.rb b/app/controllers/settings/exports_controller.rb
index ae62f00c1e2..9c03ece8600 100644
--- a/app/controllers/settings/exports_controller.rb
+++ b/app/controllers/settings/exports_controller.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
-class Settings::ExportsController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
-
+class Settings::ExportsController < Settings::BaseController
def show
@export = Export.new(current_account)
end
diff --git a/app/controllers/settings/follower_domains_controller.rb b/app/controllers/settings/follower_domains_controller.rb
index 9968504e5f7..141b2270dd5 100644
--- a/app/controllers/settings/follower_domains_controller.rb
+++ b/app/controllers/settings/follower_domains_controller.rb
@@ -2,11 +2,7 @@
require 'sidekiq-bulk'
-class Settings::FollowerDomainsController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
-
+class Settings::FollowerDomainsController < Settings::BaseController
def show
@account = current_account
@domains = current_account.followers.reorder('MIN(follows.id) DESC').group('accounts.domain').select('accounts.domain, count(accounts.id) as accounts_from_domain').page(params[:page]).per(10)
diff --git a/app/controllers/settings/imports_controller.rb b/app/controllers/settings/imports_controller.rb
index 0db13d1ca64..dbd136ebe1e 100644
--- a/app/controllers/settings/imports_controller.rb
+++ b/app/controllers/settings/imports_controller.rb
@@ -1,9 +1,6 @@
# frozen_string_literal: true
-class Settings::ImportsController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
+class Settings::ImportsController < Settings::BaseController
before_action :set_account
def show
diff --git a/app/controllers/settings/keyword_mutes_controller.rb b/app/controllers/settings/keyword_mutes_controller.rb
index f79e1b320b7..699b8a3ef1c 100644
--- a/app/controllers/settings/keyword_mutes_controller.rb
+++ b/app/controllers/settings/keyword_mutes_controller.rb
@@ -1,9 +1,6 @@
# frozen_string_literal: true
-class Settings::KeywordMutesController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
+class Settings::KeywordMutesController < Settings::BaseController
before_action :load_keyword_mute, only: [:edit, :update, :destroy]
def index
diff --git a/app/controllers/settings/notifications_controller.rb b/app/controllers/settings/notifications_controller.rb
index ce2530c5416..6286e3ebf10 100644
--- a/app/controllers/settings/notifications_controller.rb
+++ b/app/controllers/settings/notifications_controller.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
-class Settings::NotificationsController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
-
+class Settings::NotificationsController < Settings::BaseController
def show; end
def update
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 0690267151c..277f0f65738 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
-class Settings::PreferencesController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
-
+class Settings::PreferencesController < Settings::BaseController
def show; end
def update
@@ -42,7 +38,8 @@ class Settings::PreferencesController < ApplicationController
:setting_reduce_motion,
:setting_system_font_ui,
:setting_noindex,
- :setting_theme,
+ :setting_flavour,
+ :setting_skin,
notification_emails: %i(follow follow_request reblog favourite mention digest),
interactions: %i(must_be_follower must_be_following)
)
diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb
index 28f78a4fb85..dadc3d91188 100644
--- a/app/controllers/settings/profiles_controller.rb
+++ b/app/controllers/settings/profiles_controller.rb
@@ -1,11 +1,8 @@
# frozen_string_literal: true
-class Settings::ProfilesController < ApplicationController
+class Settings::ProfilesController < Settings::BaseController
include ObfuscateFilename
- layout 'admin'
-
- before_action :authenticate_user!
before_action :set_account
obfuscate_filename [:account, :avatar]
diff --git a/app/controllers/settings/sessions_controller.rb b/app/controllers/settings/sessions_controller.rb
index 0da1b027b8e..780ea64b40f 100644
--- a/app/controllers/settings/sessions_controller.rb
+++ b/app/controllers/settings/sessions_controller.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
+# Intentionally does not inherit from BaseController
class Settings::SessionsController < ApplicationController
before_action :set_session, only: :destroy
diff --git a/app/controllers/settings/two_factor_authentications_controller.rb b/app/controllers/settings/two_factor_authentications_controller.rb
index 863cc7351b7..8c7737e9dc9 100644
--- a/app/controllers/settings/two_factor_authentications_controller.rb
+++ b/app/controllers/settings/two_factor_authentications_controller.rb
@@ -1,10 +1,7 @@
# frozen_string_literal: true
module Settings
- class TwoFactorAuthenticationsController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
+ class TwoFactorAuthenticationsController < BaseController
before_action :verify_otp_required, only: [:create]
def show
diff --git a/app/controllers/shares_controller.rb b/app/controllers/shares_controller.rb
index 994742c3df6..81d279c8b4c 100644
--- a/app/controllers/shares_controller.rb
+++ b/app/controllers/shares_controller.rb
@@ -4,6 +4,7 @@ class SharesController < ApplicationController
layout 'modal'
before_action :authenticate_user!
+ before_action :set_pack
before_action :set_body_classes
def show
@@ -24,6 +25,10 @@ class SharesController < ApplicationController
}
end
+ def set_pack
+ use_pack 'share'
+ end
+
def set_body_classes
@body_classes = 'compose-standalone'
end
diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb
index e8a360fb575..84c9e7685e5 100644
--- a/app/controllers/statuses_controller.rb
+++ b/app/controllers/statuses_controller.rb
@@ -14,6 +14,7 @@ class StatusesController < ApplicationController
def show
respond_to do |format|
format.html do
+ use_pack 'public'
@ancestors = @status.reply? ? cache_collection(@status.ancestors(current_account), Status) : []
@descendants = cache_collection(@status.descendants(current_account), Status)
@@ -37,6 +38,7 @@ class StatusesController < ApplicationController
end
def embed
+ use_pack 'embed'
response.headers['X-Frame-Options'] = 'ALLOWALL'
render 'stream_entries/embed', layout: 'embedded'
end
diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb
index 5f61e2182cf..b597ba4bbe5 100644
--- a/app/controllers/stream_entries_controller.rb
+++ b/app/controllers/stream_entries_controller.rb
@@ -14,6 +14,7 @@ class StreamEntriesController < ApplicationController
def show
respond_to do |format|
format.html do
+ use_pack 'public'
@ancestors = @stream_entry.activity.reply? ? cache_collection(@stream_entry.activity.ancestors(current_account), Status) : []
@descendants = cache_collection(@stream_entry.activity.descendants(current_account), Status)
end
diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb
index 9f3090e37be..5d11a813907 100644
--- a/app/controllers/tags_controller.rb
+++ b/app/controllers/tags_controller.rb
@@ -9,6 +9,7 @@ class TagsController < ApplicationController
respond_to do |format|
format.html do
+ use_pack 'about'
serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer)
@initial_state_json = serializable_resource.to_json
end
diff --git a/app/javascript/packs/admin.js b/app/javascript/core/admin.js
similarity index 95%
rename from app/javascript/packs/admin.js
rename to app/javascript/core/admin.js
index 993827db59a..c0bd09bdda2 100644
--- a/app/javascript/packs/admin.js
+++ b/app/javascript/core/admin.js
@@ -1,3 +1,5 @@
+// This file will be loaded on admin pages, regardless of theme.
+
import { delegate } from 'rails-ujs';
function handleDeleteStatus(event) {
diff --git a/app/javascript/core/common.js b/app/javascript/core/common.js
new file mode 100644
index 00000000000..a7073ef0eb9
--- /dev/null
+++ b/app/javascript/core/common.js
@@ -0,0 +1,8 @@
+// This file will be loaded on all pages, regardless of theme.
+
+import { start } from 'rails-ujs';
+import 'font-awesome/css/font-awesome.css';
+
+require.context('../images/', true);
+
+start();
diff --git a/app/javascript/core/embed.js b/app/javascript/core/embed.js
new file mode 100644
index 00000000000..6146e65929d
--- /dev/null
+++ b/app/javascript/core/embed.js
@@ -0,0 +1,23 @@
+// This file will be loaded on embed pages, regardless of theme.
+
+window.addEventListener('message', e => {
+ const data = e.data || {};
+
+ if (!window.parent || data.type !== 'setHeight') {
+ return;
+ }
+
+ function setEmbedHeight () {
+ window.parent.postMessage({
+ type: 'setHeight',
+ id: data.id,
+ height: document.getElementsByTagName('html')[0].scrollHeight,
+ }, '*');
+ };
+
+ if (['interactive', 'complete'].includes(document.readyState)) {
+ setEmbedHeight();
+ } else {
+ document.addEventListener('DOMContentLoaded', setEmbedHeight);
+ }
+});
diff --git a/app/javascript/core/public.js b/app/javascript/core/public.js
new file mode 100644
index 00000000000..47c34a25909
--- /dev/null
+++ b/app/javascript/core/public.js
@@ -0,0 +1,25 @@
+// This file will be loaded on public pages, regardless of theme.
+
+const { delegate } = require('rails-ujs');
+
+delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
+ if (button !== 0) {
+ return true;
+ }
+ window.location.href = target.href;
+ return false;
+});
+
+delegate(document, '.status__content__spoiler-link', 'click', ({ target }) => {
+ const contentEl = target.parentNode.parentNode.querySelector('.e-content');
+
+ if (contentEl.style.display === 'block') {
+ contentEl.style.display = 'none';
+ target.parentNode.style.marginBottom = 0;
+ } else {
+ contentEl.style.display = 'block';
+ target.parentNode.style.marginBottom = null;
+ }
+
+ return false;
+});
diff --git a/app/javascript/core/settings.js b/app/javascript/core/settings.js
new file mode 100644
index 00000000000..ada5fba2b1d
--- /dev/null
+++ b/app/javascript/core/settings.js
@@ -0,0 +1,43 @@
+// This file will be loaded on settings pages, regardless of theme.
+
+const { length } = require('stringz');
+const { delegate } = require('rails-ujs');
+
+import { processBio } from 'flavours/glitch/util/bio_metadata';
+
+delegate(document, '.account_display_name', 'input', ({ target }) => {
+ const nameCounter = document.querySelector('.name-counter');
+
+ if (nameCounter) {
+ nameCounter.textContent = 30 - length(target.value);
+ }
+});
+
+delegate(document, '.account_note', 'input', ({ target }) => {
+ const noteCounter = document.querySelector('.note-counter');
+
+ if (noteCounter) {
+ const noteWithoutMetadata = processBio(target.value).text;
+ noteCounter.textContent = 500 - length(noteWithoutMetadata);
+ }
+});
+
+delegate(document, '#account_avatar', 'change', ({ target }) => {
+ const avatar = document.querySelector('.card.compact .avatar img');
+ const [file] = target.files || [];
+ const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;
+
+ avatar.src = url;
+});
+
+delegate(document, '#account_header', 'change', ({ target }) => {
+ const header = document.querySelector('.card.compact');
+ const [file] = target.files || [];
+ const url = file ? URL.createObjectURL(file) : header.dataset.originalSrc;
+
+ header.style.backgroundImage = `url(${url})`;
+});
+
+delegate(document, '#user_setting_flavour, #user_setting_skin', 'change', ({ target }) => {
+ target.form.submit();
+});
diff --git a/app/javascript/core/theme.yml b/app/javascript/core/theme.yml
new file mode 100644
index 00000000000..0dc05a1493b
--- /dev/null
+++ b/app/javascript/core/theme.yml
@@ -0,0 +1,16 @@
+# These packs will be loaded on every appropriate page, regardless of
+# theme.
+pack:
+ about:
+ admin: admin.js
+ auth:
+ common:
+ filename: common.js
+ stylesheet: true
+ embed: embed.js
+ error:
+ home:
+ modal:
+ public: public.js
+ settings: settings.js
+ share:
diff --git a/app/javascript/themes/glitch/actions/accounts.js b/app/javascript/flavours/glitch/actions/accounts.js
similarity index 99%
rename from app/javascript/themes/glitch/actions/accounts.js
rename to app/javascript/flavours/glitch/actions/accounts.js
index f1a8c5471e1..8ab92f9e7ad 100644
--- a/app/javascript/themes/glitch/actions/accounts.js
+++ b/app/javascript/flavours/glitch/actions/accounts.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'themes/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/util/api';
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';
diff --git a/app/javascript/themes/glitch/actions/alerts.js b/app/javascript/flavours/glitch/actions/alerts.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/alerts.js
rename to app/javascript/flavours/glitch/actions/alerts.js
diff --git a/app/javascript/themes/glitch/actions/blocks.js b/app/javascript/flavours/glitch/actions/blocks.js
similarity index 97%
rename from app/javascript/themes/glitch/actions/blocks.js
rename to app/javascript/flavours/glitch/actions/blocks.js
index 6ba9460f02a..fe44ca19a0f 100644
--- a/app/javascript/themes/glitch/actions/blocks.js
+++ b/app/javascript/flavours/glitch/actions/blocks.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'themes/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/util/api';
import { fetchRelationships } from './accounts';
export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
diff --git a/app/javascript/themes/glitch/actions/bundles.js b/app/javascript/flavours/glitch/actions/bundles.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/bundles.js
rename to app/javascript/flavours/glitch/actions/bundles.js
diff --git a/app/javascript/themes/glitch/actions/cards.js b/app/javascript/flavours/glitch/actions/cards.js
similarity index 96%
rename from app/javascript/themes/glitch/actions/cards.js
rename to app/javascript/flavours/glitch/actions/cards.js
index 2a1bc369a35..c897daf58d1 100644
--- a/app/javascript/themes/glitch/actions/cards.js
+++ b/app/javascript/flavours/glitch/actions/cards.js
@@ -1,4 +1,4 @@
-import api from 'themes/glitch/util/api';
+import api from 'flavours/glitch/util/api';
export const STATUS_CARD_FETCH_REQUEST = 'STATUS_CARD_FETCH_REQUEST';
export const STATUS_CARD_FETCH_SUCCESS = 'STATUS_CARD_FETCH_SUCCESS';
diff --git a/app/javascript/themes/glitch/actions/columns.js b/app/javascript/flavours/glitch/actions/columns.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/columns.js
rename to app/javascript/flavours/glitch/actions/columns.js
diff --git a/app/javascript/themes/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js
similarity index 98%
rename from app/javascript/themes/glitch/actions/compose.js
rename to app/javascript/flavours/glitch/actions/compose.js
index 07c46947731..32746f27b62 100644
--- a/app/javascript/themes/glitch/actions/compose.js
+++ b/app/javascript/flavours/glitch/actions/compose.js
@@ -1,6 +1,6 @@
-import api from 'themes/glitch/util/api';
+import api from 'flavours/glitch/util/api';
import { throttle } from 'lodash';
-import { search as emojiSearch } from 'themes/glitch/util/emoji/emoji_mart_search_light';
+import { search as emojiSearch } from 'flavours/glitch/util/emoji/emoji_mart_search_light';
import { useEmoji } from './emojis';
import {
diff --git a/app/javascript/themes/glitch/actions/domain_blocks.js b/app/javascript/flavours/glitch/actions/domain_blocks.js
similarity index 97%
rename from app/javascript/themes/glitch/actions/domain_blocks.js
rename to app/javascript/flavours/glitch/actions/domain_blocks.js
index 0a880394a83..8506df91c93 100644
--- a/app/javascript/themes/glitch/actions/domain_blocks.js
+++ b/app/javascript/flavours/glitch/actions/domain_blocks.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'themes/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/util/api';
export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';
export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';
diff --git a/app/javascript/themes/glitch/actions/emojis.js b/app/javascript/flavours/glitch/actions/emojis.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/emojis.js
rename to app/javascript/flavours/glitch/actions/emojis.js
diff --git a/app/javascript/themes/glitch/actions/favourites.js b/app/javascript/flavours/glitch/actions/favourites.js
similarity index 97%
rename from app/javascript/themes/glitch/actions/favourites.js
rename to app/javascript/flavours/glitch/actions/favourites.js
index e9b3559af6b..decdcee4f2a 100644
--- a/app/javascript/themes/glitch/actions/favourites.js
+++ b/app/javascript/flavours/glitch/actions/favourites.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'themes/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/util/api';
export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST';
export const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS';
diff --git a/app/javascript/themes/glitch/actions/height_cache.js b/app/javascript/flavours/glitch/actions/height_cache.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/height_cache.js
rename to app/javascript/flavours/glitch/actions/height_cache.js
diff --git a/app/javascript/themes/glitch/actions/interactions.js b/app/javascript/flavours/glitch/actions/interactions.js
similarity index 99%
rename from app/javascript/themes/glitch/actions/interactions.js
rename to app/javascript/flavours/glitch/actions/interactions.js
index d61a7ba2ad4..ceeb2773bdb 100644
--- a/app/javascript/themes/glitch/actions/interactions.js
+++ b/app/javascript/flavours/glitch/actions/interactions.js
@@ -1,4 +1,4 @@
-import api from 'themes/glitch/util/api';
+import api from 'flavours/glitch/util/api';
export const REBLOG_REQUEST = 'REBLOG_REQUEST';
export const REBLOG_SUCCESS = 'REBLOG_SUCCESS';
diff --git a/app/javascript/themes/glitch/actions/local_settings.js b/app/javascript/flavours/glitch/actions/local_settings.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/local_settings.js
rename to app/javascript/flavours/glitch/actions/local_settings.js
diff --git a/app/javascript/themes/glitch/actions/modal.js b/app/javascript/flavours/glitch/actions/modal.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/modal.js
rename to app/javascript/flavours/glitch/actions/modal.js
diff --git a/app/javascript/themes/glitch/actions/mutes.js b/app/javascript/flavours/glitch/actions/mutes.js
similarity index 95%
rename from app/javascript/themes/glitch/actions/mutes.js
rename to app/javascript/flavours/glitch/actions/mutes.js
index bb19e865777..e061305336c 100644
--- a/app/javascript/themes/glitch/actions/mutes.js
+++ b/app/javascript/flavours/glitch/actions/mutes.js
@@ -1,6 +1,6 @@
-import api, { getLinks } from 'themes/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/util/api';
import { fetchRelationships } from './accounts';
-import { openModal } from 'themes/glitch/actions/modal';
+import { openModal } from 'flavours/glitch/actions/modal';
export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
diff --git a/app/javascript/themes/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js
similarity index 99%
rename from app/javascript/themes/glitch/actions/notifications.js
rename to app/javascript/flavours/glitch/actions/notifications.js
index fbf06f7c42f..9b9ebf86d10 100644
--- a/app/javascript/themes/glitch/actions/notifications.js
+++ b/app/javascript/flavours/glitch/actions/notifications.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'themes/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/util/api';
import { List as ImmutableList } from 'immutable';
import IntlMessageFormat from 'intl-messageformat';
import { fetchRelationships } from './accounts';
diff --git a/app/javascript/themes/glitch/actions/onboarding.js b/app/javascript/flavours/glitch/actions/onboarding.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/onboarding.js
rename to app/javascript/flavours/glitch/actions/onboarding.js
diff --git a/app/javascript/themes/glitch/actions/pin_statuses.js b/app/javascript/flavours/glitch/actions/pin_statuses.js
similarity index 90%
rename from app/javascript/themes/glitch/actions/pin_statuses.js
rename to app/javascript/flavours/glitch/actions/pin_statuses.js
index b3e064e586a..d3d1a154f62 100644
--- a/app/javascript/themes/glitch/actions/pin_statuses.js
+++ b/app/javascript/flavours/glitch/actions/pin_statuses.js
@@ -1,10 +1,10 @@
-import api from 'themes/glitch/util/api';
+import api from 'flavours/glitch/util/api';
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
export function fetchPinnedStatuses() {
return (dispatch, getState) => {
diff --git a/app/javascript/themes/glitch/actions/push_notifications.js b/app/javascript/flavours/glitch/actions/push_notifications.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/push_notifications.js
rename to app/javascript/flavours/glitch/actions/push_notifications.js
diff --git a/app/javascript/themes/glitch/actions/reports.js b/app/javascript/flavours/glitch/actions/reports.js
similarity index 97%
rename from app/javascript/themes/glitch/actions/reports.js
rename to app/javascript/flavours/glitch/actions/reports.js
index 93f9085b2ca..ad4fd18a931 100644
--- a/app/javascript/themes/glitch/actions/reports.js
+++ b/app/javascript/flavours/glitch/actions/reports.js
@@ -1,4 +1,4 @@
-import api from 'themes/glitch/util/api';
+import api from 'flavours/glitch/util/api';
import { openModal, closeModal } from './modal';
export const REPORT_INIT = 'REPORT_INIT';
diff --git a/app/javascript/themes/glitch/actions/search.js b/app/javascript/flavours/glitch/actions/search.js
similarity index 96%
rename from app/javascript/themes/glitch/actions/search.js
rename to app/javascript/flavours/glitch/actions/search.js
index 414e4755ebc..e86bd848e56 100644
--- a/app/javascript/themes/glitch/actions/search.js
+++ b/app/javascript/flavours/glitch/actions/search.js
@@ -1,4 +1,4 @@
-import api from 'themes/glitch/util/api';
+import api from 'flavours/glitch/util/api';
export const SEARCH_CHANGE = 'SEARCH_CHANGE';
export const SEARCH_CLEAR = 'SEARCH_CLEAR';
diff --git a/app/javascript/themes/glitch/actions/settings.js b/app/javascript/flavours/glitch/actions/settings.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/settings.js
rename to app/javascript/flavours/glitch/actions/settings.js
diff --git a/app/javascript/themes/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js
similarity index 99%
rename from app/javascript/themes/glitch/actions/statuses.js
rename to app/javascript/flavours/glitch/actions/statuses.js
index 702f4e9b6ff..8b49083ac26 100644
--- a/app/javascript/themes/glitch/actions/statuses.js
+++ b/app/javascript/flavours/glitch/actions/statuses.js
@@ -1,4 +1,4 @@
-import api from 'themes/glitch/util/api';
+import api from 'flavours/glitch/util/api';
import { deleteFromTimelines } from './timelines';
import { fetchStatusCard } from './cards';
diff --git a/app/javascript/themes/glitch/actions/store.js b/app/javascript/flavours/glitch/actions/store.js
similarity index 100%
rename from app/javascript/themes/glitch/actions/store.js
rename to app/javascript/flavours/glitch/actions/store.js
diff --git a/app/javascript/themes/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js
similarity index 96%
rename from app/javascript/themes/glitch/actions/streaming.js
rename to app/javascript/flavours/glitch/actions/streaming.js
index ccf6c27d825..595eefa41f7 100644
--- a/app/javascript/themes/glitch/actions/streaming.js
+++ b/app/javascript/flavours/glitch/actions/streaming.js
@@ -1,4 +1,4 @@
-import { connectStream } from 'themes/glitch/util/stream';
+import { connectStream } from 'flavours/glitch/util/stream';
import {
updateTimeline,
deleteFromTimelines,
diff --git a/app/javascript/themes/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js
similarity index 99%
rename from app/javascript/themes/glitch/actions/timelines.js
rename to app/javascript/flavours/glitch/actions/timelines.js
index 5ce14fbe9f1..3fabf388581 100644
--- a/app/javascript/themes/glitch/actions/timelines.js
+++ b/app/javascript/flavours/glitch/actions/timelines.js
@@ -1,4 +1,4 @@
-import api, { getLinks } from 'themes/glitch/util/api';
+import api, { getLinks } from 'flavours/glitch/util/api';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
diff --git a/app/javascript/themes/glitch/components/account.js b/app/javascript/flavours/glitch/components/account.js
similarity index 98%
rename from app/javascript/themes/glitch/components/account.js
rename to app/javascript/flavours/glitch/components/account.js
index d0ff7705043..c8dacb0ab93 100644
--- a/app/javascript/themes/glitch/components/account.js
+++ b/app/javascript/flavours/glitch/components/account.js
@@ -7,7 +7,7 @@ import Permalink from './permalink';
import IconButton from './icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
follow: { id: 'account.follow', defaultMessage: 'Follow' },
diff --git a/app/javascript/themes/glitch/components/attachment_list.js b/app/javascript/flavours/glitch/components/attachment_list.js
similarity index 100%
rename from app/javascript/themes/glitch/components/attachment_list.js
rename to app/javascript/flavours/glitch/components/attachment_list.js
diff --git a/app/javascript/themes/glitch/components/autosuggest_emoji.js b/app/javascript/flavours/glitch/components/autosuggest_emoji.js
similarity index 90%
rename from app/javascript/themes/glitch/components/autosuggest_emoji.js
rename to app/javascript/flavours/glitch/components/autosuggest_emoji.js
index 3c6f915e408..79e113d9cf0 100644
--- a/app/javascript/themes/glitch/components/autosuggest_emoji.js
+++ b/app/javascript/flavours/glitch/components/autosuggest_emoji.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import unicodeMapping from 'themes/glitch/util/emoji/emoji_unicode_mapping_light';
+import unicodeMapping from 'flavours/glitch/util/emoji/emoji_unicode_mapping_light';
const assetHost = process.env.CDN_HOST || '';
diff --git a/app/javascript/themes/glitch/components/autosuggest_textarea.js b/app/javascript/flavours/glitch/components/autosuggest_textarea.js
similarity index 97%
rename from app/javascript/themes/glitch/components/autosuggest_textarea.js
rename to app/javascript/flavours/glitch/components/autosuggest_textarea.js
index fa93847a236..551528e5ace 100644
--- a/app/javascript/themes/glitch/components/autosuggest_textarea.js
+++ b/app/javascript/flavours/glitch/components/autosuggest_textarea.js
@@ -1,9 +1,9 @@
import React from 'react';
-import AutosuggestAccountContainer from 'themes/glitch/features/compose/containers/autosuggest_account_container';
+import AutosuggestAccountContainer from 'flavours/glitch/features/compose/containers/autosuggest_account_container';
import AutosuggestEmoji from './autosuggest_emoji';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import { isRtl } from 'themes/glitch/util/rtl';
+import { isRtl } from 'flavours/glitch/util/rtl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Textarea from 'react-textarea-autosize';
import classNames from 'classnames';
diff --git a/app/javascript/themes/glitch/components/avatar.js b/app/javascript/flavours/glitch/components/avatar.js
similarity index 100%
rename from app/javascript/themes/glitch/components/avatar.js
rename to app/javascript/flavours/glitch/components/avatar.js
diff --git a/app/javascript/themes/glitch/components/avatar_overlay.js b/app/javascript/flavours/glitch/components/avatar_overlay.js
similarity index 100%
rename from app/javascript/themes/glitch/components/avatar_overlay.js
rename to app/javascript/flavours/glitch/components/avatar_overlay.js
diff --git a/app/javascript/themes/glitch/components/button.js b/app/javascript/flavours/glitch/components/button.js
similarity index 100%
rename from app/javascript/themes/glitch/components/button.js
rename to app/javascript/flavours/glitch/components/button.js
diff --git a/app/javascript/themes/glitch/components/collapsable.js b/app/javascript/flavours/glitch/components/collapsable.js
similarity index 92%
rename from app/javascript/themes/glitch/components/collapsable.js
rename to app/javascript/flavours/glitch/components/collapsable.js
index 8bc0a54f4f2..fe125a729a1 100644
--- a/app/javascript/themes/glitch/components/collapsable.js
+++ b/app/javascript/flavours/glitch/components/collapsable.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import PropTypes from 'prop-types';
diff --git a/app/javascript/themes/glitch/components/column.js b/app/javascript/flavours/glitch/components/column.js
similarity index 95%
rename from app/javascript/themes/glitch/components/column.js
rename to app/javascript/flavours/glitch/components/column.js
index adeba9cc114..57c4c7a4048 100644
--- a/app/javascript/themes/glitch/components/column.js
+++ b/app/javascript/flavours/glitch/components/column.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import detectPassiveEvents from 'detect-passive-events';
-import { scrollTop } from 'themes/glitch/util/scroll';
+import { scrollTop } from 'flavours/glitch/util/scroll';
export default class Column extends React.PureComponent {
diff --git a/app/javascript/themes/glitch/components/column_back_button.js b/app/javascript/flavours/glitch/components/column_back_button.js
similarity index 100%
rename from app/javascript/themes/glitch/components/column_back_button.js
rename to app/javascript/flavours/glitch/components/column_back_button.js
diff --git a/app/javascript/themes/glitch/components/column_back_button_slim.js b/app/javascript/flavours/glitch/components/column_back_button_slim.js
similarity index 100%
rename from app/javascript/themes/glitch/components/column_back_button_slim.js
rename to app/javascript/flavours/glitch/components/column_back_button_slim.js
diff --git a/app/javascript/themes/glitch/components/column_header.js b/app/javascript/flavours/glitch/components/column_header.js
similarity index 98%
rename from app/javascript/themes/glitch/components/column_header.js
rename to app/javascript/flavours/glitch/components/column_header.js
index e601082c851..ae90b6f81ff 100644
--- a/app/javascript/themes/glitch/components/column_header.js
+++ b/app/javascript/flavours/glitch/components/column_header.js
@@ -4,8 +4,7 @@ import classNames from 'classnames';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
-// Glitch imports
-import NotificationPurgeButtonsContainer from 'themes/glitch/containers/notification_purge_buttons_container';
+import NotificationPurgeButtonsContainer from 'flavours/glitch/containers/notification_purge_buttons_container';
const messages = defineMessages({
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
diff --git a/app/javascript/themes/glitch/components/display_name.js b/app/javascript/flavours/glitch/components/display_name.js
similarity index 100%
rename from app/javascript/themes/glitch/components/display_name.js
rename to app/javascript/flavours/glitch/components/display_name.js
diff --git a/app/javascript/themes/glitch/components/dropdown_menu.js b/app/javascript/flavours/glitch/components/dropdown_menu.js
similarity index 98%
rename from app/javascript/themes/glitch/components/dropdown_menu.js
rename to app/javascript/flavours/glitch/components/dropdown_menu.js
index d30dc2aaf63..d4a886a8b30 100644
--- a/app/javascript/themes/glitch/components/dropdown_menu.js
+++ b/app/javascript/flavours/glitch/components/dropdown_menu.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import IconButton from './icon_button';
import Overlay from 'react-overlays/lib/Overlay';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import detectPassiveEvents from 'detect-passive-events';
diff --git a/app/javascript/themes/glitch/components/extended_video_player.js b/app/javascript/flavours/glitch/components/extended_video_player.js
similarity index 100%
rename from app/javascript/themes/glitch/components/extended_video_player.js
rename to app/javascript/flavours/glitch/components/extended_video_player.js
diff --git a/app/javascript/themes/glitch/components/icon_button.js b/app/javascript/flavours/glitch/components/icon_button.js
similarity index 98%
rename from app/javascript/themes/glitch/components/icon_button.js
rename to app/javascript/flavours/glitch/components/icon_button.js
index 31cdf470364..13b91e8a1fe 100644
--- a/app/javascript/themes/glitch/components/icon_button.js
+++ b/app/javascript/flavours/glitch/components/icon_button.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import PropTypes from 'prop-types';
import classNames from 'classnames';
diff --git a/app/javascript/themes/glitch/components/intersection_observer_article.js b/app/javascript/flavours/glitch/components/intersection_observer_article.js
similarity index 96%
rename from app/javascript/themes/glitch/components/intersection_observer_article.js
rename to app/javascript/flavours/glitch/components/intersection_observer_article.js
index f0139ac7543..8b06f9a8c81 100644
--- a/app/javascript/themes/glitch/components/intersection_observer_article.js
+++ b/app/javascript/flavours/glitch/components/intersection_observer_article.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
-import scheduleIdleTask from 'themes/glitch/util/schedule_idle_task';
-import getRectFromEntry from 'themes/glitch/util/get_rect_from_entry';
+import scheduleIdleTask from 'flavours/glitch/util/schedule_idle_task';
+import getRectFromEntry from 'flavours/glitch/util/get_rect_from_entry';
import { is } from 'immutable';
// Diff these props in the "rendered" state
diff --git a/app/javascript/themes/glitch/components/load_more.js b/app/javascript/flavours/glitch/components/load_more.js
similarity index 100%
rename from app/javascript/themes/glitch/components/load_more.js
rename to app/javascript/flavours/glitch/components/load_more.js
diff --git a/app/javascript/themes/glitch/components/loading_indicator.js b/app/javascript/flavours/glitch/components/loading_indicator.js
similarity index 100%
rename from app/javascript/themes/glitch/components/loading_indicator.js
rename to app/javascript/flavours/glitch/components/loading_indicator.js
diff --git a/app/javascript/themes/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js
similarity index 98%
rename from app/javascript/themes/glitch/components/media_gallery.js
rename to app/javascript/flavours/glitch/components/media_gallery.js
index b6b40c5855a..d2e80de4964 100644
--- a/app/javascript/themes/glitch/components/media_gallery.js
+++ b/app/javascript/flavours/glitch/components/media_gallery.js
@@ -4,9 +4,9 @@ import PropTypes from 'prop-types';
import { is } from 'immutable';
import IconButton from './icon_button';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { isIOS } from 'themes/glitch/util/is_mobile';
+import { isIOS } from 'flavours/glitch/util/is_mobile';
import classNames from 'classnames';
-import { autoPlayGif } from 'themes/glitch/util/initial_state';
+import { autoPlayGif } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
diff --git a/app/javascript/themes/glitch/components/missing_indicator.js b/app/javascript/flavours/glitch/components/missing_indicator.js
similarity index 100%
rename from app/javascript/themes/glitch/components/missing_indicator.js
rename to app/javascript/flavours/glitch/components/missing_indicator.js
diff --git a/app/javascript/themes/glitch/components/notification_purge_buttons.js b/app/javascript/flavours/glitch/components/notification_purge_buttons.js
similarity index 100%
rename from app/javascript/themes/glitch/components/notification_purge_buttons.js
rename to app/javascript/flavours/glitch/components/notification_purge_buttons.js
diff --git a/app/javascript/themes/glitch/components/permalink.js b/app/javascript/flavours/glitch/components/permalink.js
similarity index 100%
rename from app/javascript/themes/glitch/components/permalink.js
rename to app/javascript/flavours/glitch/components/permalink.js
diff --git a/app/javascript/themes/glitch/components/relative_timestamp.js b/app/javascript/flavours/glitch/components/relative_timestamp.js
similarity index 100%
rename from app/javascript/themes/glitch/components/relative_timestamp.js
rename to app/javascript/flavours/glitch/components/relative_timestamp.js
diff --git a/app/javascript/themes/glitch/components/scrollable_list.js b/app/javascript/flavours/glitch/components/scrollable_list.js
similarity index 95%
rename from app/javascript/themes/glitch/components/scrollable_list.js
rename to app/javascript/flavours/glitch/components/scrollable_list.js
index ccdcd7c854a..8b1e3c93dd9 100644
--- a/app/javascript/themes/glitch/components/scrollable_list.js
+++ b/app/javascript/flavours/glitch/components/scrollable_list.js
@@ -1,13 +1,13 @@
import React, { PureComponent } from 'react';
import { ScrollContainer } from 'react-router-scroll-4';
import PropTypes from 'prop-types';
-import IntersectionObserverArticleContainer from 'themes/glitch/containers/intersection_observer_article_container';
+import IntersectionObserverArticleContainer from 'flavours/glitch/containers/intersection_observer_article_container';
import LoadMore from './load_more';
-import IntersectionObserverWrapper from 'themes/glitch/util/intersection_observer_wrapper';
+import IntersectionObserverWrapper from 'flavours/glitch/util/intersection_observer_wrapper';
import { throttle } from 'lodash';
import { List as ImmutableList } from 'immutable';
import classNames from 'classnames';
-import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'themes/glitch/util/fullscreen';
+import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
export default class ScrollableList extends PureComponent {
diff --git a/app/javascript/themes/glitch/components/setting_text.js b/app/javascript/flavours/glitch/components/setting_text.js
similarity index 100%
rename from app/javascript/themes/glitch/components/setting_text.js
rename to app/javascript/flavours/glitch/components/setting_text.js
diff --git a/app/javascript/themes/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
similarity index 98%
rename from app/javascript/themes/glitch/components/status.js
rename to app/javascript/flavours/glitch/components/status.js
index 9288bcafa4a..b0d9e375769 100644
--- a/app/javascript/themes/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -6,9 +6,9 @@ import StatusHeader from './status_header';
import StatusContent from './status_content';
import StatusActionBar from './status_action_bar';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { MediaGallery, Video } from 'themes/glitch/util/async-components';
+import { MediaGallery, Video } from 'flavours/glitch/util/async-components';
import { HotKeys } from 'react-hotkeys';
-import NotificationOverlayContainer from 'themes/glitch/features/notifications/containers/overlay_container';
+import NotificationOverlayContainer from 'flavours/glitch/features/notifications/containers/overlay_container';
import classNames from 'classnames';
// We use the component (and not the container) since we do not want
diff --git a/app/javascript/themes/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js
similarity index 96%
rename from app/javascript/themes/glitch/components/status_action_bar.js
rename to app/javascript/flavours/glitch/components/status_action_bar.js
index 9d615ed7cfd..5a06782bec4 100644
--- a/app/javascript/themes/glitch/components/status_action_bar.js
+++ b/app/javascript/flavours/glitch/components/status_action_bar.js
@@ -1,14 +1,11 @@
-// THIS FILE EXISTS FOR UPSTREAM COMPATIBILITY & SHOULDN'T BE USED !!
-// SEE INSTEAD : glitch/components/status/action_bar
-
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import IconButton from './icon_button';
-import DropdownMenuContainer from 'themes/glitch/containers/dropdown_menu_container';
+import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
import RelativeTimestamp from './relative_timestamp';
const messages = defineMessages({
diff --git a/app/javascript/themes/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js
similarity index 99%
rename from app/javascript/themes/glitch/components/status_content.js
rename to app/javascript/flavours/glitch/components/status_content.js
index 3eba6eaa0ed..0c40e62ccae 100644
--- a/app/javascript/themes/glitch/components/status_content.js
+++ b/app/javascript/flavours/glitch/components/status_content.js
@@ -1,7 +1,7 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import { isRtl } from 'themes/glitch/util/rtl';
+import { isRtl } from 'flavours/glitch/util/rtl';
import { FormattedMessage } from 'react-intl';
import Permalink from './permalink';
import classnames from 'classnames';
diff --git a/app/javascript/themes/glitch/components/status_header.js b/app/javascript/flavours/glitch/components/status_header.js
similarity index 100%
rename from app/javascript/themes/glitch/components/status_header.js
rename to app/javascript/flavours/glitch/components/status_header.js
diff --git a/app/javascript/themes/glitch/components/status_list.js b/app/javascript/flavours/glitch/components/status_list.js
similarity index 95%
rename from app/javascript/themes/glitch/components/status_list.js
rename to app/javascript/flavours/glitch/components/status_list.js
index ddb1354c674..f190ba6ab61 100644
--- a/app/javascript/themes/glitch/components/status_list.js
+++ b/app/javascript/flavours/glitch/components/status_list.js
@@ -1,7 +1,7 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import StatusContainer from 'themes/glitch/containers/status_container';
+import StatusContainer from 'flavours/glitch/containers/status_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ScrollableList from './scrollable_list';
diff --git a/app/javascript/themes/glitch/components/status_prepend.js b/app/javascript/flavours/glitch/components/status_prepend.js
similarity index 100%
rename from app/javascript/themes/glitch/components/status_prepend.js
rename to app/javascript/flavours/glitch/components/status_prepend.js
diff --git a/app/javascript/themes/glitch/components/status_visibility_icon.js b/app/javascript/flavours/glitch/components/status_visibility_icon.js
similarity index 100%
rename from app/javascript/themes/glitch/components/status_visibility_icon.js
rename to app/javascript/flavours/glitch/components/status_visibility_icon.js
diff --git a/app/javascript/themes/glitch/containers/account_container.js b/app/javascript/flavours/glitch/containers/account_container.js
similarity index 84%
rename from app/javascript/themes/glitch/containers/account_container.js
rename to app/javascript/flavours/glitch/containers/account_container.js
index c1ce4998715..bc84d299b49 100644
--- a/app/javascript/themes/glitch/containers/account_container.js
+++ b/app/javascript/flavours/glitch/containers/account_container.js
@@ -1,8 +1,8 @@
import React from 'react';
import { connect } from 'react-redux';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { makeGetAccount } from 'themes/glitch/selectors';
-import Account from 'themes/glitch/components/account';
+import { makeGetAccount } from 'flavours/glitch/selectors';
+import Account from 'flavours/glitch/components/account';
import {
followAccount,
unfollowAccount,
@@ -10,10 +10,10 @@ import {
unblockAccount,
muteAccount,
unmuteAccount,
-} from 'themes/glitch/actions/accounts';
-import { openModal } from 'themes/glitch/actions/modal';
-import { initMuteModal } from 'themes/glitch/actions/mutes';
-import { unfollowModal } from 'themes/glitch/util/initial_state';
+} from 'flavours/glitch/actions/accounts';
+import { openModal } from 'flavours/glitch/actions/modal';
+import { initMuteModal } from 'flavours/glitch/actions/mutes';
+import { unfollowModal } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
diff --git a/app/javascript/themes/glitch/containers/card_container.js b/app/javascript/flavours/glitch/containers/card_container.js
similarity index 84%
rename from app/javascript/themes/glitch/containers/card_container.js
rename to app/javascript/flavours/glitch/containers/card_container.js
index 8285437bbfc..dec7df52236 100644
--- a/app/javascript/themes/glitch/containers/card_container.js
+++ b/app/javascript/flavours/glitch/containers/card_container.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Card from 'themes/glitch/features/status/components/card';
+import Card from 'flavours/glitch/features/status/components/card';
import { fromJS } from 'immutable';
export default class CardContainer extends React.PureComponent {
diff --git a/app/javascript/themes/glitch/containers/compose_container.js b/app/javascript/flavours/glitch/containers/compose_container.js
similarity index 74%
rename from app/javascript/themes/glitch/containers/compose_container.js
rename to app/javascript/flavours/glitch/containers/compose_container.js
index 82980ee36f3..60f6a9c9f2c 100644
--- a/app/javascript/themes/glitch/containers/compose_container.js
+++ b/app/javascript/flavours/glitch/containers/compose_container.js
@@ -1,12 +1,12 @@
import React from 'react';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
-import configureStore from 'themes/glitch/store/configureStore';
-import { hydrateStore } from 'themes/glitch/actions/store';
+import configureStore from 'flavours/glitch/store/configureStore';
+import { hydrateStore } from 'flavours/glitch/actions/store';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from 'mastodon/locales';
-import Compose from 'themes/glitch/features/standalone/compose';
-import initialState from 'themes/glitch/util/initial_state';
+import Compose from 'flavours/glitch/features/standalone/compose';
+import initialState from 'flavours/glitch/util/initial_state';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
diff --git a/app/javascript/themes/glitch/containers/dropdown_menu_container.js b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js
similarity index 65%
rename from app/javascript/themes/glitch/containers/dropdown_menu_container.js
rename to app/javascript/flavours/glitch/containers/dropdown_menu_container.js
index 15e8da2e3a0..0b4f72fa163 100644
--- a/app/javascript/themes/glitch/containers/dropdown_menu_container.js
+++ b/app/javascript/flavours/glitch/containers/dropdown_menu_container.js
@@ -1,7 +1,7 @@
-import { openModal, closeModal } from 'themes/glitch/actions/modal';
+import { openModal, closeModal } from 'flavours/glitch/actions/modal';
import { connect } from 'react-redux';
-import DropdownMenu from 'themes/glitch/components/dropdown_menu';
-import { isUserTouching } from 'themes/glitch/util/is_mobile';
+import DropdownMenu from 'flavours/glitch/components/dropdown_menu';
+import { isUserTouching } from 'flavours/glitch/util/is_mobile';
const mapStateToProps = state => ({
isModalOpen: state.get('modal').modalType === 'ACTIONS',
diff --git a/app/javascript/themes/glitch/containers/intersection_observer_article_container.js b/app/javascript/flavours/glitch/containers/intersection_observer_article_container.js
similarity index 70%
rename from app/javascript/themes/glitch/containers/intersection_observer_article_container.js
rename to app/javascript/flavours/glitch/containers/intersection_observer_article_container.js
index 6ede64738b2..f2741f2d4ff 100644
--- a/app/javascript/themes/glitch/containers/intersection_observer_article_container.js
+++ b/app/javascript/flavours/glitch/containers/intersection_observer_article_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
-import IntersectionObserverArticle from 'themes/glitch/components/intersection_observer_article';
-import { setHeight } from 'themes/glitch/actions/height_cache';
+import IntersectionObserverArticle from 'flavours/glitch/components/intersection_observer_article';
+import { setHeight } from 'flavours/glitch/actions/height_cache';
const makeMapStateToProps = (state, props) => ({
cachedHeight: state.getIn(['height_cache', props.saveHeightKey, props.id]),
diff --git a/app/javascript/themes/glitch/containers/mastodon.js b/app/javascript/flavours/glitch/containers/mastodon.js
similarity index 81%
rename from app/javascript/themes/glitch/containers/mastodon.js
rename to app/javascript/flavours/glitch/containers/mastodon.js
index 3484706378a..1c98cd5f75d 100644
--- a/app/javascript/themes/glitch/containers/mastodon.js
+++ b/app/javascript/flavours/glitch/containers/mastodon.js
@@ -1,16 +1,16 @@
import React from 'react';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
-import configureStore from 'themes/glitch/store/configureStore';
-import { showOnboardingOnce } from 'themes/glitch/actions/onboarding';
+import configureStore from 'flavours/glitch/store/configureStore';
+import { showOnboardingOnce } from 'flavours/glitch/actions/onboarding';
import { BrowserRouter, Route } from 'react-router-dom';
import { ScrollContext } from 'react-router-scroll-4';
-import UI from 'themes/glitch/features/ui';
-import { hydrateStore } from 'themes/glitch/actions/store';
-import { connectUserStream } from 'themes/glitch/actions/streaming';
+import UI from 'flavours/glitch/features/ui';
+import { hydrateStore } from 'flavours/glitch/actions/store';
+import { connectUserStream } from 'flavours/glitch/actions/streaming';
import { IntlProvider, addLocaleData } from 'react-intl';
-import { getLocale } from 'mastodon/locales';
-import initialState from 'themes/glitch/util/initial_state';
+import { getLocale } from 'locales';
+import initialState from 'flavours/glitch/util/initial_state';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
diff --git a/app/javascript/themes/glitch/containers/media_gallery_container.js b/app/javascript/flavours/glitch/containers/media_gallery_container.js
similarity index 92%
rename from app/javascript/themes/glitch/containers/media_gallery_container.js
rename to app/javascript/flavours/glitch/containers/media_gallery_container.js
index 86965f73b3b..54bfbf4535a 100644
--- a/app/javascript/themes/glitch/containers/media_gallery_container.js
+++ b/app/javascript/flavours/glitch/containers/media_gallery_container.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from 'mastodon/locales';
-import MediaGallery from 'themes/glitch/components/media_gallery';
+import MediaGallery from 'flavours/glitch/components/media_gallery';
import { fromJS } from 'immutable';
const { localeData, messages } = getLocale();
diff --git a/app/javascript/themes/glitch/containers/notification_purge_buttons_container.js b/app/javascript/flavours/glitch/containers/notification_purge_buttons_container.js
similarity index 86%
rename from app/javascript/themes/glitch/containers/notification_purge_buttons_container.js
rename to app/javascript/flavours/glitch/containers/notification_purge_buttons_container.js
index ee4cb84cdf1..2570cf4a567 100644
--- a/app/javascript/themes/glitch/containers/notification_purge_buttons_container.js
+++ b/app/javascript/flavours/glitch/containers/notification_purge_buttons_container.js
@@ -3,13 +3,13 @@ import { connect } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl';
// Our imports.
-import NotificationPurgeButtons from 'themes/glitch/components/notification_purge_buttons';
+import NotificationPurgeButtons from 'flavours/glitch/components/notification_purge_buttons';
import {
deleteMarkedNotifications,
enterNotificationClearingMode,
markAllNotifications,
-} from 'themes/glitch/actions/notifications';
-import { openModal } from 'themes/glitch/actions/modal';
+} from 'flavours/glitch/actions/notifications';
+import { openModal } from 'flavours/glitch/actions/modal';
const messages = defineMessages({
clearMessage: { id: 'notifications.marked_clear_confirmation', defaultMessage: 'Are you sure you want to permanently clear all selected notifications?' },
diff --git a/app/javascript/themes/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js
similarity index 85%
rename from app/javascript/themes/glitch/containers/status_container.js
rename to app/javascript/flavours/glitch/containers/status_container.js
index 0cee73b9a43..b753de7b3a5 100644
--- a/app/javascript/themes/glitch/containers/status_container.js
+++ b/app/javascript/flavours/glitch/containers/status_container.js
@@ -1,11 +1,11 @@
import React from 'react';
import { connect } from 'react-redux';
-import Status from 'themes/glitch/components/status';
-import { makeGetStatus } from 'themes/glitch/selectors';
+import Status from 'flavours/glitch/components/status';
+import { makeGetStatus } from 'flavours/glitch/selectors';
import {
replyCompose,
mentionCompose,
-} from 'themes/glitch/actions/compose';
+} from 'flavours/glitch/actions/compose';
import {
reblog,
favourite,
@@ -13,14 +13,14 @@ import {
unfavourite,
pin,
unpin,
-} from 'themes/glitch/actions/interactions';
-import { blockAccount } from 'themes/glitch/actions/accounts';
-import { muteStatus, unmuteStatus, deleteStatus } from 'themes/glitch/actions/statuses';
-import { initMuteModal } from 'themes/glitch/actions/mutes';
-import { initReport } from 'themes/glitch/actions/reports';
-import { openModal } from 'themes/glitch/actions/modal';
+} from 'flavours/glitch/actions/interactions';
+import { blockAccount } from 'flavours/glitch/actions/accounts';
+import { muteStatus, unmuteStatus, deleteStatus } from 'flavours/glitch/actions/statuses';
+import { initMuteModal } from 'flavours/glitch/actions/mutes';
+import { initReport } from 'flavours/glitch/actions/reports';
+import { openModal } from 'flavours/glitch/actions/modal';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { boostModal, deleteModal } from 'themes/glitch/util/initial_state';
+import { boostModal, deleteModal } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
diff --git a/app/javascript/themes/glitch/containers/timeline_container.js b/app/javascript/flavours/glitch/containers/timeline_container.js
similarity index 72%
rename from app/javascript/themes/glitch/containers/timeline_container.js
rename to app/javascript/flavours/glitch/containers/timeline_container.js
index a75f8808dc4..c5ffe1b6330 100644
--- a/app/javascript/themes/glitch/containers/timeline_container.js
+++ b/app/javascript/flavours/glitch/containers/timeline_container.js
@@ -1,13 +1,13 @@
import React from 'react';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
-import configureStore from 'themes/glitch/store/configureStore';
-import { hydrateStore } from 'themes/glitch/actions/store';
+import configureStore from 'flavours/glitch/store/configureStore';
+import { hydrateStore } from 'flavours/glitch/actions/store';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from 'mastodon/locales';
-import PublicTimeline from 'themes/glitch/features/standalone/public_timeline';
-import HashtagTimeline from 'themes/glitch/features/standalone/hashtag_timeline';
-import initialState from 'themes/glitch/util/initial_state';
+import PublicTimeline from 'flavours/glitch/features/standalone/public_timeline';
+import HashtagTimeline from 'flavours/glitch/features/standalone/hashtag_timeline';
+import initialState from 'flavours/glitch/util/initial_state';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
diff --git a/app/javascript/themes/glitch/containers/video_container.js b/app/javascript/flavours/glitch/containers/video_container.js
similarity index 91%
rename from app/javascript/themes/glitch/containers/video_container.js
rename to app/javascript/flavours/glitch/containers/video_container.js
index 2b0e9866621..b206e9a1001 100644
--- a/app/javascript/themes/glitch/containers/video_container.js
+++ b/app/javascript/flavours/glitch/containers/video_container.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from 'mastodon/locales';
-import Video from 'themes/glitch/features/video';
+import Video from 'flavours/glitch/features/video';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
diff --git a/app/javascript/themes/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js
similarity index 97%
rename from app/javascript/themes/glitch/features/account/components/action_bar.js
rename to app/javascript/flavours/glitch/features/account/components/action_bar.js
index 0edd5c8481d..7c9c1af4e8d 100644
--- a/app/javascript/themes/glitch/features/account/components/action_bar.js
+++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js
@@ -1,10 +1,10 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import DropdownMenuContainer from 'themes/glitch/containers/dropdown_menu_container';
+import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
import { Link } from 'react-router-dom';
import { defineMessages, injectIntl, FormattedMessage, FormattedNumber } from 'react-intl';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
diff --git a/app/javascript/themes/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js
similarity index 92%
rename from app/javascript/themes/glitch/features/account/components/header.js
rename to app/javascript/flavours/glitch/features/account/components/header.js
index 696bb199190..f5ecaae71e9 100644
--- a/app/javascript/themes/glitch/features/account/components/header.js
+++ b/app/javascript/flavours/glitch/features/account/components/header.js
@@ -4,12 +4,12 @@ import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import Avatar from 'themes/glitch/components/avatar';
-import IconButton from 'themes/glitch/components/icon_button';
+import Avatar from 'flavours/glitch/components/avatar';
+import IconButton from 'flavours/glitch/components/icon_button';
-import emojify from 'themes/glitch/util/emoji';
-import { me } from 'themes/glitch/util/initial_state';
-import { processBio } from 'themes/glitch/util/bio_metadata';
+import emojify from 'flavours/glitch/util/emoji';
+import { me } from 'flavours/glitch/util/initial_state';
+import { processBio } from 'flavours/glitch/util/bio_metadata';
const messages = defineMessages({
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
diff --git a/app/javascript/themes/glitch/features/account_gallery/components/media_item.js b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
similarity index 93%
rename from app/javascript/themes/glitch/features/account_gallery/components/media_item.js
rename to app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
index 88c9156b5e8..e52d3b0bb0c 100644
--- a/app/javascript/themes/glitch/features/account_gallery/components/media_item.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.js
@@ -1,7 +1,7 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import Permalink from 'themes/glitch/components/permalink';
+import Permalink from 'flavours/glitch/components/permalink';
export default class MediaItem extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js
similarity index 84%
rename from app/javascript/themes/glitch/features/account_gallery/index.js
rename to app/javascript/flavours/glitch/features/account_gallery/index.js
index a21c089da73..951e019e370 100644
--- a/app/javascript/themes/glitch/features/account_gallery/index.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/index.js
@@ -2,18 +2,18 @@ import React from 'react';
import { connect } from 'react-redux';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import { fetchAccount } from 'themes/glitch/actions/accounts';
-import { refreshAccountMediaTimeline, expandAccountMediaTimeline } from 'themes/glitch/actions/timelines';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnBackButton from 'themes/glitch/components/column_back_button';
+import { fetchAccount } from 'flavours/glitch/actions/accounts';
+import { refreshAccountMediaTimeline, expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnBackButton from 'flavours/glitch/components/column_back_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { getAccountGallery } from 'themes/glitch/selectors';
+import { getAccountGallery } from 'flavours/glitch/selectors';
import MediaItem from './components/media_item';
-import HeaderContainer from 'themes/glitch/features/account_timeline/containers/header_container';
+import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
import { FormattedMessage } from 'react-intl';
import { ScrollContainer } from 'react-router-scroll-4';
-import LoadMore from 'themes/glitch/components/load_more';
+import LoadMore from 'flavours/glitch/components/load_more';
const mapStateToProps = (state, props) => ({
medias: getAccountGallery(state, props.params.accountId),
diff --git a/app/javascript/themes/glitch/features/account_timeline/components/header.js b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
similarity index 90%
rename from app/javascript/themes/glitch/features/account_timeline/components/header.js
rename to app/javascript/flavours/glitch/features/account_timeline/components/header.js
index c719a7bcba9..4ad677fbeb8 100644
--- a/app/javascript/themes/glitch/features/account_timeline/components/header.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
@@ -1,9 +1,9 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import InnerHeader from 'themes/glitch/features/account/components/header';
-import ActionBar from 'themes/glitch/features/account/components/action_bar';
-import MissingIndicator from 'themes/glitch/components/missing_indicator';
+import InnerHeader from 'flavours/glitch/features/account/components/header';
+import ActionBar from 'flavours/glitch/features/account/components/action_bar';
+import MissingIndicator from 'flavours/glitch/components/missing_indicator';
import ImmutablePureComponent from 'react-immutable-pure-component';
export default class Header extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/account_timeline/containers/header_container.js b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
similarity index 86%
rename from app/javascript/themes/glitch/features/account_timeline/containers/header_container.js
rename to app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
index 766b57b564a..815a1a6136d 100644
--- a/app/javascript/themes/glitch/features/account_timeline/containers/header_container.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/containers/header_container.js
@@ -1,6 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
-import { makeGetAccount } from 'themes/glitch/selectors';
+import { makeGetAccount } from 'flavours/glitch/selectors';
import Header from '../components/header';
import {
followAccount,
@@ -8,14 +8,14 @@ import {
blockAccount,
unblockAccount,
unmuteAccount,
-} from 'themes/glitch/actions/accounts';
-import { mentionCompose } from 'themes/glitch/actions/compose';
-import { initMuteModal } from 'themes/glitch/actions/mutes';
-import { initReport } from 'themes/glitch/actions/reports';
-import { openModal } from 'themes/glitch/actions/modal';
-import { blockDomain, unblockDomain } from 'themes/glitch/actions/domain_blocks';
+} from 'flavours/glitch/actions/accounts';
+import { mentionCompose } from 'flavours/glitch/actions/compose';
+import { initMuteModal } from 'flavours/glitch/actions/mutes';
+import { initReport } from 'flavours/glitch/actions/reports';
+import { openModal } from 'flavours/glitch/actions/modal';
+import { blockDomain, unblockDomain } from 'flavours/glitch/actions/domain_blocks';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import { unfollowModal } from 'themes/glitch/util/initial_state';
+import { unfollowModal } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
diff --git a/app/javascript/themes/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js
similarity index 93%
rename from app/javascript/themes/glitch/features/account_timeline/index.js
rename to app/javascript/flavours/glitch/features/account_timeline/index.js
index 81336ef3a25..75dba504901 100644
--- a/app/javascript/themes/glitch/features/account_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/index.js
@@ -2,8 +2,8 @@ import React from 'react';
import { connect } from 'react-redux';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import { fetchAccount } from 'themes/glitch/actions/accounts';
-import { refreshAccountTimeline, expandAccountTimeline } from 'themes/glitch/actions/timelines';
+import { fetchAccount } from 'flavours/glitch/actions/accounts';
+import { refreshAccountTimeline, expandAccountTimeline } from 'flavours/glitch/actions/timelines';
import StatusList from '../../components/status_list';
import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column';
diff --git a/app/javascript/themes/glitch/features/blocks/index.js b/app/javascript/flavours/glitch/features/blocks/index.js
similarity index 81%
rename from app/javascript/themes/glitch/features/blocks/index.js
rename to app/javascript/flavours/glitch/features/blocks/index.js
index 70630818c61..edd448921e4 100644
--- a/app/javascript/themes/glitch/features/blocks/index.js
+++ b/app/javascript/flavours/glitch/features/blocks/index.js
@@ -2,12 +2,12 @@ import React from 'react';
import { connect } from 'react-redux';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
import { ScrollContainer } from 'react-router-scroll-4';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnBackButtonSlim from 'themes/glitch/components/column_back_button_slim';
-import AccountContainer from 'themes/glitch/containers/account_container';
-import { fetchBlocks, expandBlocks } from 'themes/glitch/actions/blocks';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
+import AccountContainer from 'flavours/glitch/containers/account_container';
+import { fetchBlocks, expandBlocks } from 'flavours/glitch/actions/blocks';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/community_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js
similarity index 94%
rename from app/javascript/themes/glitch/features/community_timeline/components/column_settings.js
rename to app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js
index 988e3630826..6dc292ee546 100644
--- a/app/javascript/themes/glitch/features/community_timeline/components/column_settings.js
+++ b/app/javascript/flavours/glitch/features/community_timeline/components/column_settings.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import SettingText from 'themes/glitch/components/setting_text';
+import SettingText from 'flavours/glitch/components/setting_text';
const messages = defineMessages({
filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' },
diff --git a/app/javascript/themes/glitch/features/community_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/community_timeline/containers/column_settings_container.js
similarity index 86%
rename from app/javascript/themes/glitch/features/community_timeline/containers/column_settings_container.js
rename to app/javascript/flavours/glitch/features/community_timeline/containers/column_settings_container.js
index cd9c3436527..84234a836ba 100644
--- a/app/javascript/themes/glitch/features/community_timeline/containers/column_settings_container.js
+++ b/app/javascript/flavours/glitch/features/community_timeline/containers/column_settings_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import ColumnSettings from '../components/column_settings';
-import { changeSetting } from 'themes/glitch/actions/settings';
+import { changeSetting } from 'flavours/glitch/actions/settings';
const mapStateToProps = state => ({
settings: state.getIn(['settings', 'community']),
diff --git a/app/javascript/themes/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js
similarity index 85%
rename from app/javascript/themes/glitch/features/community_timeline/index.js
rename to app/javascript/flavours/glitch/features/community_timeline/index.js
index 9d255bd01cc..55355414f46 100644
--- a/app/javascript/themes/glitch/features/community_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/community_timeline/index.js
@@ -1,17 +1,17 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import StatusListContainer from 'themes/glitch/features/ui/containers/status_list_container';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
import {
refreshCommunityTimeline,
expandCommunityTimeline,
-} from 'themes/glitch/actions/timelines';
-import { addColumn, removeColumn, moveColumn } from 'themes/glitch/actions/columns';
+} from 'flavours/glitch/actions/timelines';
+import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnSettingsContainer from './containers/column_settings_container';
-import { connectCommunityStream } from 'themes/glitch/actions/streaming';
+import { connectCommunityStream } from 'flavours/glitch/actions/streaming';
const messages = defineMessages({
title: { id: 'column.community', defaultMessage: 'Local timeline' },
diff --git a/app/javascript/themes/glitch/features/compose/components/advanced_options.js b/app/javascript/flavours/glitch/features/compose/components/advanced_options.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/components/advanced_options.js
rename to app/javascript/flavours/glitch/features/compose/components/advanced_options.js
diff --git a/app/javascript/themes/glitch/features/compose/components/advanced_options_toggle.js b/app/javascript/flavours/glitch/features/compose/components/advanced_options_toggle.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/components/advanced_options_toggle.js
rename to app/javascript/flavours/glitch/features/compose/components/advanced_options_toggle.js
diff --git a/app/javascript/themes/glitch/features/compose/components/attach_options.js b/app/javascript/flavours/glitch/features/compose/components/attach_options.js
similarity index 96%
rename from app/javascript/themes/glitch/features/compose/components/attach_options.js
rename to app/javascript/flavours/glitch/features/compose/components/attach_options.js
index c396714f3a8..6c7a1f55f68 100644
--- a/app/javascript/themes/glitch/features/compose/components/attach_options.js
+++ b/app/javascript/flavours/glitch/features/compose/components/attach_options.js
@@ -6,10 +6,10 @@ import { injectIntl, defineMessages } from 'react-intl';
// Our imports //
import ComposeDropdown from './dropdown';
-import { uploadCompose } from 'themes/glitch/actions/compose';
+import { uploadCompose } from 'flavours/glitch/actions/compose';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { openModal } from 'themes/glitch/actions/modal';
+import { openModal } from 'flavours/glitch/actions/modal';
const messages = defineMessages({
upload :
diff --git a/app/javascript/themes/glitch/features/compose/components/autosuggest_account.js b/app/javascript/flavours/glitch/features/compose/components/autosuggest_account.js
similarity index 82%
rename from app/javascript/themes/glitch/features/compose/components/autosuggest_account.js
rename to app/javascript/flavours/glitch/features/compose/components/autosuggest_account.js
index 4a98d89fec6..3d474af30e5 100644
--- a/app/javascript/themes/glitch/features/compose/components/autosuggest_account.js
+++ b/app/javascript/flavours/glitch/features/compose/components/autosuggest_account.js
@@ -1,6 +1,6 @@
import React from 'react';
-import Avatar from 'themes/glitch/components/avatar';
-import DisplayName from 'themes/glitch/components/display_name';
+import Avatar from 'flavours/glitch/components/avatar';
+import DisplayName from 'flavours/glitch/components/display_name';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/compose/components/character_counter.js b/app/javascript/flavours/glitch/features/compose/components/character_counter.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/components/character_counter.js
rename to app/javascript/flavours/glitch/features/compose/components/character_counter.js
diff --git a/app/javascript/themes/glitch/features/compose/components/compose_form.js b/app/javascript/flavours/glitch/features/compose/components/compose_form.js
similarity index 96%
rename from app/javascript/themes/glitch/features/compose/components/compose_form.js
rename to app/javascript/flavours/glitch/features/compose/components/compose_form.js
index 54b1944a465..67ce935f43c 100644
--- a/app/javascript/themes/glitch/features/compose/components/compose_form.js
+++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.js
@@ -1,12 +1,12 @@
import React from 'react';
import CharacterCounter from './character_counter';
-import Button from 'themes/glitch/components/button';
+import Button from 'flavours/glitch/components/button';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import ReplyIndicatorContainer from '../containers/reply_indicator_container';
-import AutosuggestTextarea from 'themes/glitch/components/autosuggest_textarea';
+import AutosuggestTextarea from 'flavours/glitch/components/autosuggest_textarea';
import { defineMessages, injectIntl } from 'react-intl';
-import Collapsable from 'themes/glitch/components/collapsable';
+import Collapsable from 'flavours/glitch/components/collapsable';
import SpoilerButtonContainer from '../containers/spoiler_button_container';
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
import ComposeAdvancedOptionsContainer from '../containers/advanced_options_container';
@@ -14,12 +14,12 @@ import SensitiveButtonContainer from '../containers/sensitive_button_container';
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
import UploadFormContainer from '../containers/upload_form_container';
import WarningContainer from '../containers/warning_container';
-import { isMobile } from 'themes/glitch/util/is_mobile';
+import { isMobile } from 'flavours/glitch/util/is_mobile';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { length } from 'stringz';
-import { countableText } from 'themes/glitch/util/counter';
+import { countableText } from 'flavours/glitch/util/counter';
import ComposeAttachOptions from './attach_options';
-import initialState from 'themes/glitch/util/initial_state';
+import initialState from 'flavours/glitch/util/initial_state';
const maxChars = initialState.max_toot_chars;
diff --git a/app/javascript/themes/glitch/features/compose/components/dropdown.js b/app/javascript/flavours/glitch/features/compose/components/dropdown.js
similarity index 96%
rename from app/javascript/themes/glitch/features/compose/components/dropdown.js
rename to app/javascript/flavours/glitch/features/compose/components/dropdown.js
index f3d9f094e54..1b0000fb7f9 100644
--- a/app/javascript/themes/glitch/features/compose/components/dropdown.js
+++ b/app/javascript/flavours/glitch/features/compose/components/dropdown.js
@@ -3,7 +3,7 @@ import React from 'react';
import PropTypes from 'prop-types';
// Our imports.
-import IconButton from 'themes/glitch/components/icon_button';
+import IconButton from 'flavours/glitch/components/icon_button';
const iconStyle = {
height : null,
diff --git a/app/javascript/themes/glitch/features/compose/components/emoji_picker_dropdown.js b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js
similarity index 98%
rename from app/javascript/themes/glitch/features/compose/components/emoji_picker_dropdown.js
rename to app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js
index fd59efb8512..cf89f91d336 100644
--- a/app/javascript/themes/glitch/features/compose/components/emoji_picker_dropdown.js
+++ b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.js
@@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
-import { EmojiPicker as EmojiPickerAsync } from 'themes/glitch/util/async-components';
+import { EmojiPicker as EmojiPickerAsync } from 'flavours/glitch/util/async-components';
import Overlay from 'react-overlays/lib/Overlay';
import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import detectPassiveEvents from 'detect-passive-events';
-import { buildCustomEmojis } from 'themes/glitch/util/emoji';
+import { buildCustomEmojis } from 'flavours/glitch/util/emoji';
const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
diff --git a/app/javascript/themes/glitch/features/compose/components/navigation_bar.js b/app/javascript/flavours/glitch/features/compose/components/navigation_bar.js
similarity index 87%
rename from app/javascript/themes/glitch/features/compose/components/navigation_bar.js
rename to app/javascript/flavours/glitch/features/compose/components/navigation_bar.js
index 24a70949b86..1b6d74123e7 100644
--- a/app/javascript/themes/glitch/features/compose/components/navigation_bar.js
+++ b/app/javascript/flavours/glitch/features/compose/components/navigation_bar.js
@@ -1,9 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import Avatar from 'themes/glitch/components/avatar';
-import IconButton from 'themes/glitch/components/icon_button';
-import Permalink from 'themes/glitch/components/permalink';
+import Avatar from 'flavours/glitch/components/avatar';
+import IconButton from 'flavours/glitch/components/icon_button';
+import Permalink from 'flavours/glitch/components/permalink';
import { FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/compose/components/privacy_dropdown.js b/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.js
similarity index 98%
rename from app/javascript/themes/glitch/features/compose/components/privacy_dropdown.js
rename to app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.js
index 0cd92d174f4..90f062f8f08 100644
--- a/app/javascript/themes/glitch/features/compose/components/privacy_dropdown.js
+++ b/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.js
@@ -1,9 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, defineMessages } from 'react-intl';
-import IconButton from 'themes/glitch/components/icon_button';
+import IconButton from 'flavours/glitch/components/icon_button';
import Overlay from 'react-overlays/lib/Overlay';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import detectPassiveEvents from 'detect-passive-events';
import classNames from 'classnames';
diff --git a/app/javascript/themes/glitch/features/compose/components/reply_indicator.js b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.js
similarity index 90%
rename from app/javascript/themes/glitch/features/compose/components/reply_indicator.js
rename to app/javascript/flavours/glitch/features/compose/components/reply_indicator.js
index 9a8d10cebc7..cb28e51be1e 100644
--- a/app/javascript/themes/glitch/features/compose/components/reply_indicator.js
+++ b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.js
@@ -1,9 +1,9 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import Avatar from 'themes/glitch/components/avatar';
-import IconButton from 'themes/glitch/components/icon_button';
-import DisplayName from 'themes/glitch/components/display_name';
+import Avatar from 'flavours/glitch/components/avatar';
+import IconButton from 'flavours/glitch/components/icon_button';
+import DisplayName from 'flavours/glitch/components/display_name';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/compose/components/search.js b/app/javascript/flavours/glitch/features/compose/components/search.js
similarity index 98%
rename from app/javascript/themes/glitch/features/compose/components/search.js
rename to app/javascript/flavours/glitch/features/compose/components/search.js
index c3218137f88..1ce66b19dad 100644
--- a/app/javascript/themes/glitch/features/compose/components/search.js
+++ b/app/javascript/flavours/glitch/features/compose/components/search.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Overlay from 'react-overlays/lib/Overlay';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
const messages = defineMessages({
diff --git a/app/javascript/themes/glitch/features/compose/components/search_results.js b/app/javascript/flavours/glitch/features/compose/components/search_results.js
similarity index 93%
rename from app/javascript/themes/glitch/features/compose/components/search_results.js
rename to app/javascript/flavours/glitch/features/compose/components/search_results.js
index 3fdafa5f3c1..2a4818d4e29 100644
--- a/app/javascript/themes/glitch/features/compose/components/search_results.js
+++ b/app/javascript/flavours/glitch/features/compose/components/search_results.js
@@ -1,8 +1,8 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
-import AccountContainer from 'themes/glitch/containers/account_container';
-import StatusContainer from 'themes/glitch/containers/status_container';
+import AccountContainer from 'flavours/glitch/containers/account_container';
+import StatusContainer from 'flavours/glitch/containers/status_container';
import { Link } from 'react-router-dom';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/compose/components/text_icon_button.js b/app/javascript/flavours/glitch/features/compose/components/text_icon_button.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/components/text_icon_button.js
rename to app/javascript/flavours/glitch/features/compose/components/text_icon_button.js
diff --git a/app/javascript/themes/glitch/features/compose/components/upload.js b/app/javascript/flavours/glitch/features/compose/components/upload.js
similarity index 96%
rename from app/javascript/themes/glitch/features/compose/components/upload.js
rename to app/javascript/flavours/glitch/features/compose/components/upload.js
index ded376ada35..a1fc93234c1 100644
--- a/app/javascript/themes/glitch/features/compose/components/upload.js
+++ b/app/javascript/flavours/glitch/features/compose/components/upload.js
@@ -1,8 +1,8 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import IconButton from 'themes/glitch/components/icon_button';
-import Motion from 'themes/glitch/util/optional_motion';
+import IconButton from 'flavours/glitch/components/icon_button';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl } from 'react-intl';
diff --git a/app/javascript/themes/glitch/features/compose/components/upload_button.js b/app/javascript/flavours/glitch/features/compose/components/upload_button.js
similarity index 97%
rename from app/javascript/themes/glitch/features/compose/components/upload_button.js
rename to app/javascript/flavours/glitch/features/compose/components/upload_button.js
index d7742adfe76..f06167a2a98 100644
--- a/app/javascript/themes/glitch/features/compose/components/upload_button.js
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_button.js
@@ -1,5 +1,5 @@
import React from 'react';
-import IconButton from 'themes/glitch/components/icon_button';
+import IconButton from 'flavours/glitch/components/icon_button';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
diff --git a/app/javascript/themes/glitch/features/compose/components/upload_form.js b/app/javascript/flavours/glitch/features/compose/components/upload_form.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/components/upload_form.js
rename to app/javascript/flavours/glitch/features/compose/components/upload_form.js
diff --git a/app/javascript/themes/glitch/features/compose/components/upload_progress.js b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
similarity index 94%
rename from app/javascript/themes/glitch/features/compose/components/upload_progress.js
rename to app/javascript/flavours/glitch/features/compose/components/upload_progress.js
index b923d0a2269..2a3b8ceb481 100644
--- a/app/javascript/themes/glitch/features/compose/components/upload_progress.js
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_progress.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import { FormattedMessage } from 'react-intl';
diff --git a/app/javascript/themes/glitch/features/compose/components/warning.js b/app/javascript/flavours/glitch/features/compose/components/warning.js
similarity index 93%
rename from app/javascript/themes/glitch/features/compose/components/warning.js
rename to app/javascript/flavours/glitch/features/compose/components/warning.js
index 82df55a31d2..4962e76c8ad 100644
--- a/app/javascript/themes/glitch/features/compose/components/warning.js
+++ b/app/javascript/flavours/glitch/features/compose/components/warning.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
export default class Warning extends React.PureComponent {
diff --git a/app/javascript/themes/glitch/features/compose/containers/advanced_options_container.js b/app/javascript/flavours/glitch/features/compose/containers/advanced_options_container.js
similarity index 85%
rename from app/javascript/themes/glitch/features/compose/containers/advanced_options_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/advanced_options_container.js
index 9f168942a0a..da381568b2b 100644
--- a/app/javascript/themes/glitch/features/compose/containers/advanced_options_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/advanced_options_container.js
@@ -2,7 +2,7 @@
import { connect } from 'react-redux';
// Our imports.
-import { toggleComposeAdvancedOption } from 'themes/glitch/actions/compose';
+import { toggleComposeAdvancedOption } from 'flavours/glitch/actions/compose';
import ComposeAdvancedOptions from '../components/advanced_options';
const mapStateToProps = state => ({
diff --git a/app/javascript/themes/glitch/features/compose/containers/autosuggest_account_container.js b/app/javascript/flavours/glitch/features/compose/containers/autosuggest_account_container.js
similarity index 86%
rename from app/javascript/themes/glitch/features/compose/containers/autosuggest_account_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/autosuggest_account_container.js
index 96eb70c185f..0e1c328fe90 100644
--- a/app/javascript/themes/glitch/features/compose/containers/autosuggest_account_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/autosuggest_account_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import AutosuggestAccount from '../components/autosuggest_account';
-import { makeGetAccount } from 'themes/glitch/selectors';
+import { makeGetAccount } from 'flavours/glitch/selectors';
const makeMapStateToProps = () => {
const getAccount = makeGetAccount();
diff --git a/app/javascript/themes/glitch/features/compose/containers/compose_form_container.js b/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
similarity index 93%
rename from app/javascript/themes/glitch/features/compose/containers/compose_form_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
index 7afa988f1fc..e2e93e44b61 100644
--- a/app/javascript/themes/glitch/features/compose/containers/compose_form_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/compose_form_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import ComposeForm from '../components/compose_form';
-import { changeComposeVisibility, uploadCompose } from 'themes/glitch/actions/compose';
+import { changeComposeVisibility, uploadCompose } from 'flavours/glitch/actions/compose';
import {
changeCompose,
submitCompose,
@@ -9,7 +9,7 @@ import {
selectComposeSuggestion,
changeComposeSpoilerText,
insertEmojiCompose,
-} from 'themes/glitch/actions/compose';
+} from 'flavours/glitch/actions/compose';
const mapStateToProps = state => ({
text: state.getIn(['compose', 'text']),
diff --git a/app/javascript/themes/glitch/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/flavours/glitch/features/compose/containers/emoji_picker_dropdown_container.js
similarity index 93%
rename from app/javascript/themes/glitch/features/compose/containers/emoji_picker_dropdown_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/emoji_picker_dropdown_container.js
index 55a13bd6539..ba85edd8737 100644
--- a/app/javascript/themes/glitch/features/compose/containers/emoji_picker_dropdown_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/emoji_picker_dropdown_container.js
@@ -1,9 +1,9 @@
import { connect } from 'react-redux';
import EmojiPickerDropdown from '../components/emoji_picker_dropdown';
-import { changeSetting } from 'themes/glitch/actions/settings';
+import { changeSetting } from 'flavours/glitch/actions/settings';
import { createSelector } from 'reselect';
import { Map as ImmutableMap } from 'immutable';
-import { useEmoji } from 'themes/glitch/actions/emojis';
+import { useEmoji } from 'flavours/glitch/actions/emojis';
const perLine = 8;
const lines = 2;
diff --git a/app/javascript/themes/glitch/features/compose/containers/navigation_container.js b/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
similarity index 81%
rename from app/javascript/themes/glitch/features/compose/containers/navigation_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
index b6d737b462d..eb630ffbb5d 100644
--- a/app/javascript/themes/glitch/features/compose/containers/navigation_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import NavigationBar from '../components/navigation_bar';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const mapStateToProps = state => {
return {
diff --git a/app/javascript/themes/glitch/features/compose/containers/privacy_dropdown_container.js b/app/javascript/flavours/glitch/features/compose/containers/privacy_dropdown_container.js
similarity index 73%
rename from app/javascript/themes/glitch/features/compose/containers/privacy_dropdown_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/privacy_dropdown_container.js
index 9636ceab244..cb94fcc8064 100644
--- a/app/javascript/themes/glitch/features/compose/containers/privacy_dropdown_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/privacy_dropdown_container.js
@@ -1,8 +1,8 @@
import { connect } from 'react-redux';
import PrivacyDropdown from '../components/privacy_dropdown';
-import { changeComposeVisibility } from 'themes/glitch/actions/compose';
-import { openModal, closeModal } from 'themes/glitch/actions/modal';
-import { isUserTouching } from 'themes/glitch/util/is_mobile';
+import { changeComposeVisibility } from 'flavours/glitch/actions/compose';
+import { openModal, closeModal } from 'flavours/glitch/actions/modal';
+import { isUserTouching } from 'flavours/glitch/util/is_mobile';
const mapStateToProps = state => ({
isModalOpen: state.get('modal').modalType === 'ACTIONS',
diff --git a/app/javascript/themes/glitch/features/compose/containers/reply_indicator_container.js b/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js
similarity index 79%
rename from app/javascript/themes/glitch/features/compose/containers/reply_indicator_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js
index 6dcabb3cd18..a7c82d135dc 100644
--- a/app/javascript/themes/glitch/features/compose/containers/reply_indicator_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
-import { cancelReplyCompose } from 'themes/glitch/actions/compose';
-import { makeGetStatus } from 'themes/glitch/selectors';
+import { cancelReplyCompose } from 'flavours/glitch/actions/compose';
+import { makeGetStatus } from 'flavours/glitch/selectors';
import ReplyIndicator from '../components/reply_indicator';
const makeMapStateToProps = () => {
diff --git a/app/javascript/themes/glitch/features/compose/containers/search_container.js b/app/javascript/flavours/glitch/features/compose/containers/search_container.js
similarity index 93%
rename from app/javascript/themes/glitch/features/compose/containers/search_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/search_container.js
index a450d27e7a4..8f4bfcf0884 100644
--- a/app/javascript/themes/glitch/features/compose/containers/search_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/search_container.js
@@ -4,7 +4,7 @@ import {
clearSearch,
submitSearch,
showSearch,
-} from 'themes/glitch/actions/search';
+} from 'flavours/glitch/actions/search';
import Search from '../components/search';
const mapStateToProps = state => ({
diff --git a/app/javascript/themes/glitch/features/compose/containers/search_results_container.js b/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/containers/search_results_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/search_results_container.js
diff --git a/app/javascript/themes/glitch/features/compose/containers/sensitive_button_container.js b/app/javascript/flavours/glitch/features/compose/containers/sensitive_button_container.js
similarity index 91%
rename from app/javascript/themes/glitch/features/compose/containers/sensitive_button_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/sensitive_button_container.js
index a710dd104f0..cf6706c0e0a 100644
--- a/app/javascript/themes/glitch/features/compose/containers/sensitive_button_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/sensitive_button_container.js
@@ -2,9 +2,9 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-import IconButton from 'themes/glitch/components/icon_button';
-import { changeComposeSensitivity } from 'themes/glitch/actions/compose';
-import Motion from 'themes/glitch/util/optional_motion';
+import IconButton from 'flavours/glitch/components/icon_button';
+import { changeComposeSensitivity } from 'flavours/glitch/actions/compose';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import { injectIntl, defineMessages } from 'react-intl';
diff --git a/app/javascript/themes/glitch/features/compose/containers/spoiler_button_container.js b/app/javascript/flavours/glitch/features/compose/containers/spoiler_button_container.js
similarity index 89%
rename from app/javascript/themes/glitch/features/compose/containers/spoiler_button_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/spoiler_button_container.js
index 160e71ba921..d7b4246bc2f 100644
--- a/app/javascript/themes/glitch/features/compose/containers/spoiler_button_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/spoiler_button_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import TextIconButton from '../components/text_icon_button';
-import { changeComposeSpoilerness } from 'themes/glitch/actions/compose';
+import { changeComposeSpoilerness } from 'flavours/glitch/actions/compose';
import { injectIntl, defineMessages } from 'react-intl';
const messages = defineMessages({
diff --git a/app/javascript/themes/glitch/features/compose/containers/upload_button_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_button_container.js
similarity index 90%
rename from app/javascript/themes/glitch/features/compose/containers/upload_button_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/upload_button_container.js
index f332eae1aad..4c1cb49e938 100644
--- a/app/javascript/themes/glitch/features/compose/containers/upload_button_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/upload_button_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import UploadButton from '../components/upload_button';
-import { uploadCompose } from 'themes/glitch/actions/compose';
+import { uploadCompose } from 'flavours/glitch/actions/compose';
const mapStateToProps = state => ({
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')),
diff --git a/app/javascript/themes/glitch/features/compose/containers/upload_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js
similarity index 84%
rename from app/javascript/themes/glitch/features/compose/containers/upload_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/upload_container.js
index eea514bf537..368038425e1 100644
--- a/app/javascript/themes/glitch/features/compose/containers/upload_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import Upload from '../components/upload';
-import { undoUploadCompose, changeUploadCompose } from 'themes/glitch/actions/compose';
+import { undoUploadCompose, changeUploadCompose } from 'flavours/glitch/actions/compose';
const mapStateToProps = (state, { id }) => ({
media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),
diff --git a/app/javascript/themes/glitch/features/compose/containers/upload_form_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_form_container.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/containers/upload_form_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/upload_form_container.js
diff --git a/app/javascript/themes/glitch/features/compose/containers/upload_progress_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js
similarity index 100%
rename from app/javascript/themes/glitch/features/compose/containers/upload_progress_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js
diff --git a/app/javascript/themes/glitch/features/compose/containers/warning_container.js b/app/javascript/flavours/glitch/features/compose/containers/warning_container.js
similarity index 94%
rename from app/javascript/themes/glitch/features/compose/containers/warning_container.js
rename to app/javascript/flavours/glitch/features/compose/containers/warning_container.js
index 225d6a1dd9c..f20c75b9115 100644
--- a/app/javascript/themes/glitch/features/compose/containers/warning_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/warning_container.js
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import Warning from '../components/warning';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const mapStateToProps = state => ({
needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
diff --git a/app/javascript/themes/glitch/features/compose/index.js b/app/javascript/flavours/glitch/features/compose/index.js
similarity index 93%
rename from app/javascript/themes/glitch/features/compose/index.js
rename to app/javascript/flavours/glitch/features/compose/index.js
index 3fcaf416f88..02b97ad00e2 100644
--- a/app/javascript/themes/glitch/features/compose/index.js
+++ b/app/javascript/flavours/glitch/features/compose/index.js
@@ -4,16 +4,16 @@ import NavigationContainer from './containers/navigation_container';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
-import { mountCompose, unmountCompose } from 'themes/glitch/actions/compose';
-import { openModal } from 'themes/glitch/actions/modal';
-import { changeLocalSetting } from 'themes/glitch/actions/local_settings';
+import { mountCompose, unmountCompose } from 'flavours/glitch/actions/compose';
+import { openModal } from 'flavours/glitch/actions/modal';
+import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
import { Link } from 'react-router-dom';
import { injectIntl, defineMessages } from 'react-intl';
import SearchContainer from './containers/search_container';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import SearchResultsContainer from './containers/search_results_container';
-import { changeComposing } from 'themes/glitch/actions/compose';
+import { changeComposing } from 'flavours/glitch/actions/compose';
const messages = defineMessages({
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
diff --git a/app/javascript/themes/glitch/features/direct_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/direct_timeline/containers/column_settings_container.js
similarity index 67%
rename from app/javascript/themes/glitch/features/direct_timeline/containers/column_settings_container.js
rename to app/javascript/flavours/glitch/features/direct_timeline/containers/column_settings_container.js
index 2a40c65a523..d3e4b421689 100644
--- a/app/javascript/themes/glitch/features/direct_timeline/containers/column_settings_container.js
+++ b/app/javascript/flavours/glitch/features/direct_timeline/containers/column_settings_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
-import ColumnSettings from 'themes/glitch/features/community_timeline/components/column_settings';
-import { changeSetting } from 'themes/glitch/actions/settings';
+import ColumnSettings from 'flavours/glitch/features/community_timeline/components/column_settings';
+import { changeSetting } from 'flavours/glitch/actions/settings';
const mapStateToProps = state => ({
settings: state.getIn(['settings', 'direct']),
diff --git a/app/javascript/themes/glitch/features/direct_timeline/index.js b/app/javascript/flavours/glitch/features/direct_timeline/index.js
similarity index 85%
rename from app/javascript/themes/glitch/features/direct_timeline/index.js
rename to app/javascript/flavours/glitch/features/direct_timeline/index.js
index 6b29cf94d2e..81096c0eced 100644
--- a/app/javascript/themes/glitch/features/direct_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/direct_timeline/index.js
@@ -1,17 +1,17 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import StatusListContainer from 'themes/glitch/features/ui/containers/status_list_container';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
import {
refreshDirectTimeline,
expandDirectTimeline,
-} from 'themes/glitch/actions/timelines';
-import { addColumn, removeColumn, moveColumn } from 'themes/glitch/actions/columns';
+} from 'flavours/glitch/actions/timelines';
+import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnSettingsContainer from './containers/column_settings_container';
-import { connectDirectStream } from 'themes/glitch/actions/streaming';
+import { connectDirectStream } from 'flavours/glitch/actions/streaming';
const messages = defineMessages({
title: { id: 'column.direct', defaultMessage: 'Direct messages' },
diff --git a/app/javascript/themes/glitch/features/favourited_statuses/index.js b/app/javascript/flavours/glitch/features/favourited_statuses/index.js
similarity index 87%
rename from app/javascript/themes/glitch/features/favourited_statuses/index.js
rename to app/javascript/flavours/glitch/features/favourited_statuses/index.js
index 80345e0e2b2..e20dda71833 100644
--- a/app/javascript/themes/glitch/features/favourited_statuses/index.js
+++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.js
@@ -2,11 +2,11 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'themes/glitch/actions/favourites';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
-import { addColumn, removeColumn, moveColumn } from 'themes/glitch/actions/columns';
-import StatusList from 'themes/glitch/components/status_list';
+import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'flavours/glitch/actions/favourites';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
+import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
+import StatusList from 'flavours/glitch/components/status_list';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js
similarity index 79%
rename from app/javascript/themes/glitch/features/favourites/index.js
rename to app/javascript/flavours/glitch/features/favourites/index.js
index d7b8ac3b10c..055a15ccb77 100644
--- a/app/javascript/themes/glitch/features/favourites/index.js
+++ b/app/javascript/flavours/glitch/features/favourites/index.js
@@ -2,12 +2,12 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
-import { fetchFavourites } from 'themes/glitch/actions/interactions';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
+import { fetchFavourites } from 'flavours/glitch/actions/interactions';
import { ScrollContainer } from 'react-router-scroll-4';
-import AccountContainer from 'themes/glitch/containers/account_container';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnBackButton from 'themes/glitch/components/column_back_button';
+import AccountContainer from 'flavours/glitch/containers/account_container';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnBackButton from 'flavours/glitch/components/column_back_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
const mapStateToProps = (state, props) => ({
diff --git a/app/javascript/themes/glitch/features/follow_requests/components/account_authorize.js b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js
similarity index 87%
rename from app/javascript/themes/glitch/features/follow_requests/components/account_authorize.js
rename to app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js
index ce386d888df..dead0753f8e 100644
--- a/app/javascript/themes/glitch/features/follow_requests/components/account_authorize.js
+++ b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.js
@@ -1,10 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import Permalink from 'themes/glitch/components/permalink';
-import Avatar from 'themes/glitch/components/avatar';
-import DisplayName from 'themes/glitch/components/display_name';
-import IconButton from 'themes/glitch/components/icon_button';
+import Permalink from 'flavours/glitch/components/permalink';
+import Avatar from 'flavours/glitch/components/avatar';
+import DisplayName from 'flavours/glitch/components/display_name';
+import IconButton from 'flavours/glitch/components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/follow_requests/containers/account_authorize_container.js b/app/javascript/flavours/glitch/features/follow_requests/containers/account_authorize_container.js
similarity index 78%
rename from app/javascript/themes/glitch/features/follow_requests/containers/account_authorize_container.js
rename to app/javascript/flavours/glitch/features/follow_requests/containers/account_authorize_container.js
index 78ae77eee3e..693e98e8ceb 100644
--- a/app/javascript/themes/glitch/features/follow_requests/containers/account_authorize_container.js
+++ b/app/javascript/flavours/glitch/features/follow_requests/containers/account_authorize_container.js
@@ -1,7 +1,7 @@
import { connect } from 'react-redux';
-import { makeGetAccount } from 'themes/glitch/selectors';
+import { makeGetAccount } from 'flavours/glitch/selectors';
import AccountAuthorize from '../components/account_authorize';
-import { authorizeFollowRequest, rejectFollowRequest } from 'themes/glitch/actions/accounts';
+import { authorizeFollowRequest, rejectFollowRequest } from 'flavours/glitch/actions/accounts';
const makeMapStateToProps = () => {
const getAccount = makeGetAccount();
diff --git a/app/javascript/themes/glitch/features/follow_requests/index.js b/app/javascript/flavours/glitch/features/follow_requests/index.js
similarity index 85%
rename from app/javascript/themes/glitch/features/follow_requests/index.js
rename to app/javascript/flavours/glitch/features/follow_requests/index.js
index 3f44f518a9c..04ff3f1116a 100644
--- a/app/javascript/themes/glitch/features/follow_requests/index.js
+++ b/app/javascript/flavours/glitch/features/follow_requests/index.js
@@ -2,12 +2,12 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
import { ScrollContainer } from 'react-router-scroll-4';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnBackButtonSlim from 'themes/glitch/components/column_back_button_slim';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
import AccountAuthorizeContainer from './containers/account_authorize_container';
-import { fetchFollowRequests, expandFollowRequests } from 'themes/glitch/actions/accounts';
+import { fetchFollowRequests, expandFollowRequests } from 'flavours/glitch/actions/accounts';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js
similarity index 83%
rename from app/javascript/themes/glitch/features/followers/index.js
rename to app/javascript/flavours/glitch/features/followers/index.js
index d586bf41d0c..f0ef29ff688 100644
--- a/app/javascript/themes/glitch/features/followers/index.js
+++ b/app/javascript/flavours/glitch/features/followers/index.js
@@ -2,18 +2,18 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
import {
fetchAccount,
fetchFollowers,
expandFollowers,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import { ScrollContainer } from 'react-router-scroll-4';
-import AccountContainer from 'themes/glitch/containers/account_container';
-import Column from 'themes/glitch/features/ui/components/column';
-import HeaderContainer from 'themes/glitch/features/account_timeline/containers/header_container';
-import LoadMore from 'themes/glitch/components/load_more';
-import ColumnBackButton from 'themes/glitch/components/column_back_button';
+import AccountContainer from 'flavours/glitch/containers/account_container';
+import Column from 'flavours/glitch/features/ui/components/column';
+import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
+import LoadMore from 'flavours/glitch/components/load_more';
+import ColumnBackButton from 'flavours/glitch/components/column_back_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
const mapStateToProps = (state, props) => ({
diff --git a/app/javascript/themes/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js
similarity index 83%
rename from app/javascript/themes/glitch/features/following/index.js
rename to app/javascript/flavours/glitch/features/following/index.js
index c306faf21da..f30f7b0d989 100644
--- a/app/javascript/themes/glitch/features/following/index.js
+++ b/app/javascript/flavours/glitch/features/following/index.js
@@ -2,18 +2,18 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
import {
fetchAccount,
fetchFollowing,
expandFollowing,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import { ScrollContainer } from 'react-router-scroll-4';
-import AccountContainer from 'themes/glitch/containers/account_container';
-import Column from 'themes/glitch/features/ui/components/column';
-import HeaderContainer from 'themes/glitch/features/account_timeline/containers/header_container';
-import LoadMore from 'themes/glitch/components/load_more';
-import ColumnBackButton from 'themes/glitch/components/column_back_button';
+import AccountContainer from 'flavours/glitch/containers/account_container';
+import Column from 'flavours/glitch/features/ui/components/column';
+import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
+import LoadMore from 'flavours/glitch/components/load_more';
+import ColumnBackButton from 'flavours/glitch/components/column_back_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
const mapStateToProps = (state, props) => ({
diff --git a/app/javascript/flavours/glitch/features/generic_not_found/index.js b/app/javascript/flavours/glitch/features/generic_not_found/index.js
new file mode 100644
index 00000000000..d01a1ba4712
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/generic_not_found/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import Column from 'flavours/glitch/features/ui/components/column';
+import MissingIndicator from 'flavours/glitch/components/missing_indicator';
+
+const GenericNotFound = () => (
+
+
+
+);
+
+export default GenericNotFound;
diff --git a/app/javascript/themes/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js
similarity index 95%
rename from app/javascript/themes/glitch/features/getting_started/index.js
rename to app/javascript/flavours/glitch/features/getting_started/index.js
index 74b019cf1c3..2af0fcf48d0 100644
--- a/app/javascript/themes/glitch/features/getting_started/index.js
+++ b/app/javascript/flavours/glitch/features/getting_started/index.js
@@ -1,14 +1,14 @@
import React from 'react';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnLink from 'themes/glitch/features/ui/components/column_link';
-import ColumnSubheading from 'themes/glitch/features/ui/components/column_subheading';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnLink from 'flavours/glitch/features/ui/components/column_link';
+import ColumnSubheading from 'flavours/glitch/features/ui/components/column_subheading';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
-import { openModal } from 'themes/glitch/actions/modal';
+import { openModal } from 'flavours/glitch/actions/modal';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
diff --git a/app/javascript/themes/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
similarity index 86%
rename from app/javascript/themes/glitch/features/hashtag_timeline/index.js
rename to app/javascript/flavours/glitch/features/hashtag_timeline/index.js
index a878931b3dd..9f3c9bec76d 100644
--- a/app/javascript/themes/glitch/features/hashtag_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
@@ -1,16 +1,16 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import StatusListContainer from 'themes/glitch/features/ui/containers/status_list_container';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
import {
refreshHashtagTimeline,
expandHashtagTimeline,
-} from 'themes/glitch/actions/timelines';
-import { addColumn, removeColumn, moveColumn } from 'themes/glitch/actions/columns';
+} from 'flavours/glitch/actions/timelines';
+import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
import { FormattedMessage } from 'react-intl';
-import { connectHashtagStream } from 'themes/glitch/actions/streaming';
+import { connectHashtagStream } from 'flavours/glitch/actions/streaming';
const mapStateToProps = (state, props) => ({
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,
diff --git a/app/javascript/themes/glitch/features/home_timeline/components/column_settings.js b/app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js
similarity index 92%
rename from app/javascript/themes/glitch/features/home_timeline/components/column_settings.js
rename to app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js
index 533da6c36cb..604a7c6dc05 100644
--- a/app/javascript/themes/glitch/features/home_timeline/components/column_settings.js
+++ b/app/javascript/flavours/glitch/features/home_timeline/components/column_settings.js
@@ -2,8 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import SettingToggle from 'themes/glitch/features/notifications/components/setting_toggle';
-import SettingText from 'themes/glitch/components/setting_text';
+import SettingToggle from 'flavours/glitch/features/notifications/components/setting_toggle';
+import SettingText from 'flavours/glitch/components/setting_text';
const messages = defineMessages({
filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' },
diff --git a/app/javascript/themes/glitch/features/home_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/home_timeline/containers/column_settings_container.js
similarity index 84%
rename from app/javascript/themes/glitch/features/home_timeline/containers/column_settings_container.js
rename to app/javascript/flavours/glitch/features/home_timeline/containers/column_settings_container.js
index a0062f564e7..19a8e792f71 100644
--- a/app/javascript/themes/glitch/features/home_timeline/containers/column_settings_container.js
+++ b/app/javascript/flavours/glitch/features/home_timeline/containers/column_settings_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import ColumnSettings from '../components/column_settings';
-import { changeSetting, saveSettings } from 'themes/glitch/actions/settings';
+import { changeSetting, saveSettings } from 'flavours/glitch/actions/settings';
const mapStateToProps = state => ({
settings: state.getIn(['settings', 'home']),
diff --git a/app/javascript/themes/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js
similarity index 86%
rename from app/javascript/themes/glitch/features/home_timeline/index.js
rename to app/javascript/flavours/glitch/features/home_timeline/index.js
index 8a65891cdbf..2dfec6bbed3 100644
--- a/app/javascript/themes/glitch/features/home_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/home_timeline/index.js
@@ -1,11 +1,11 @@
import React from 'react';
import { connect } from 'react-redux';
-import { expandHomeTimeline } from 'themes/glitch/actions/timelines';
+import { expandHomeTimeline } from 'flavours/glitch/actions/timelines';
import PropTypes from 'prop-types';
-import StatusListContainer from 'themes/glitch/features/ui/containers/status_list_container';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
-import { addColumn, removeColumn, moveColumn } from 'themes/glitch/actions/columns';
+import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
+import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnSettingsContainer from './containers/column_settings_container';
import { Link } from 'react-router-dom';
diff --git a/app/javascript/themes/glitch/features/local_settings/index.js b/app/javascript/flavours/glitch/features/local_settings/index.js
similarity index 91%
rename from app/javascript/themes/glitch/features/local_settings/index.js
rename to app/javascript/flavours/glitch/features/local_settings/index.js
index 6c5d514136a..81d9a3f4160 100644
--- a/app/javascript/themes/glitch/features/local_settings/index.js
+++ b/app/javascript/flavours/glitch/features/local_settings/index.js
@@ -7,8 +7,8 @@ import { connect } from 'react-redux';
// Our imports
import LocalSettingsPage from './page';
import LocalSettingsNavigation from './navigation';
-import { closeModal } from 'themes/glitch/actions/modal';
-import { changeLocalSetting } from 'themes/glitch/actions/local_settings';
+import { closeModal } from 'flavours/glitch/actions/modal';
+import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
// Stylesheet imports
import './style.scss';
diff --git a/app/javascript/themes/glitch/features/local_settings/navigation/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/navigation/index.js
rename to app/javascript/flavours/glitch/features/local_settings/navigation/index.js
diff --git a/app/javascript/themes/glitch/features/local_settings/navigation/item/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/navigation/item/index.js
rename to app/javascript/flavours/glitch/features/local_settings/navigation/item/index.js
diff --git a/app/javascript/themes/glitch/features/local_settings/navigation/item/style.scss b/app/javascript/flavours/glitch/features/local_settings/navigation/item/style.scss
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/navigation/item/style.scss
rename to app/javascript/flavours/glitch/features/local_settings/navigation/item/style.scss
diff --git a/app/javascript/themes/glitch/features/local_settings/navigation/style.scss b/app/javascript/flavours/glitch/features/local_settings/navigation/style.scss
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/navigation/style.scss
rename to app/javascript/flavours/glitch/features/local_settings/navigation/style.scss
diff --git a/app/javascript/themes/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/page/index.js
rename to app/javascript/flavours/glitch/features/local_settings/page/index.js
diff --git a/app/javascript/themes/glitch/features/local_settings/page/item/index.js b/app/javascript/flavours/glitch/features/local_settings/page/item/index.js
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/page/item/index.js
rename to app/javascript/flavours/glitch/features/local_settings/page/item/index.js
diff --git a/app/javascript/themes/glitch/features/local_settings/page/item/style.scss b/app/javascript/flavours/glitch/features/local_settings/page/item/style.scss
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/page/item/style.scss
rename to app/javascript/flavours/glitch/features/local_settings/page/item/style.scss
diff --git a/app/javascript/themes/glitch/features/local_settings/page/style.scss b/app/javascript/flavours/glitch/features/local_settings/page/style.scss
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/page/style.scss
rename to app/javascript/flavours/glitch/features/local_settings/page/style.scss
diff --git a/app/javascript/themes/glitch/features/local_settings/style.scss b/app/javascript/flavours/glitch/features/local_settings/style.scss
similarity index 100%
rename from app/javascript/themes/glitch/features/local_settings/style.scss
rename to app/javascript/flavours/glitch/features/local_settings/style.scss
diff --git a/app/javascript/themes/glitch/features/mutes/index.js b/app/javascript/flavours/glitch/features/mutes/index.js
similarity index 81%
rename from app/javascript/themes/glitch/features/mutes/index.js
rename to app/javascript/flavours/glitch/features/mutes/index.js
index 1158b8262ff..87517eec948 100644
--- a/app/javascript/themes/glitch/features/mutes/index.js
+++ b/app/javascript/flavours/glitch/features/mutes/index.js
@@ -2,12 +2,12 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
import { ScrollContainer } from 'react-router-scroll-4';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnBackButtonSlim from 'themes/glitch/components/column_back_button_slim';
-import AccountContainer from 'themes/glitch/containers/account_container';
-import { fetchMutes, expandMutes } from 'themes/glitch/actions/mutes';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
+import AccountContainer from 'flavours/glitch/containers/account_container';
+import { fetchMutes, expandMutes } from 'flavours/glitch/actions/mutes';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/notifications/components/clear_column_button.js b/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.js
similarity index 100%
rename from app/javascript/themes/glitch/features/notifications/components/clear_column_button.js
rename to app/javascript/flavours/glitch/features/notifications/components/clear_column_button.js
diff --git a/app/javascript/themes/glitch/features/notifications/components/column_settings.js b/app/javascript/flavours/glitch/features/notifications/components/column_settings.js
similarity index 100%
rename from app/javascript/themes/glitch/features/notifications/components/column_settings.js
rename to app/javascript/flavours/glitch/features/notifications/components/column_settings.js
diff --git a/app/javascript/themes/glitch/features/notifications/components/follow.js b/app/javascript/flavours/glitch/features/notifications/components/follow.js
similarity index 95%
rename from app/javascript/themes/glitch/features/notifications/components/follow.js
rename to app/javascript/flavours/glitch/features/notifications/components/follow.js
index 96cfe83e664..54506f67c41 100644
--- a/app/javascript/themes/glitch/features/notifications/components/follow.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/follow.js
@@ -7,8 +7,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { HotKeys } from 'react-hotkeys';
// Our imports.
-import Permalink from 'themes/glitch/components/permalink';
-import AccountContainer from 'themes/glitch/containers/account_container';
+import Permalink from 'flavours/glitch/components/permalink';
+import AccountContainer from 'flavours/glitch/containers/account_container';
import NotificationOverlayContainer from '../containers/overlay_container';
export default class NotificationFollow extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/notifications/components/notification.js b/app/javascript/flavours/glitch/features/notifications/components/notification.js
similarity index 96%
rename from app/javascript/themes/glitch/features/notifications/components/notification.js
rename to app/javascript/flavours/glitch/features/notifications/components/notification.js
index 47f5770bf06..cc77426d3b0 100644
--- a/app/javascript/themes/glitch/features/notifications/components/notification.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/notification.js
@@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
// Our imports,
-import StatusContainer from 'themes/glitch/containers/status_container';
+import StatusContainer from 'flavours/glitch/containers/status_container';
import NotificationFollow from './follow';
export default class Notification extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/notifications/components/overlay.js b/app/javascript/flavours/glitch/features/notifications/components/overlay.js
similarity index 100%
rename from app/javascript/themes/glitch/features/notifications/components/overlay.js
rename to app/javascript/flavours/glitch/features/notifications/components/overlay.js
diff --git a/app/javascript/themes/glitch/features/notifications/components/setting_toggle.js b/app/javascript/flavours/glitch/features/notifications/components/setting_toggle.js
similarity index 100%
rename from app/javascript/themes/glitch/features/notifications/components/setting_toggle.js
rename to app/javascript/flavours/glitch/features/notifications/components/setting_toggle.js
diff --git a/app/javascript/themes/glitch/features/notifications/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js
similarity index 81%
rename from app/javascript/themes/glitch/features/notifications/containers/column_settings_container.js
rename to app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js
index ddc8495f480..ce502700c45 100644
--- a/app/javascript/themes/glitch/features/notifications/containers/column_settings_container.js
+++ b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js
@@ -1,10 +1,10 @@
import { connect } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl';
import ColumnSettings from '../components/column_settings';
-import { changeSetting, saveSettings } from 'themes/glitch/actions/settings';
-import { clearNotifications } from 'themes/glitch/actions/notifications';
-import { changeAlerts as changePushNotifications, saveSettings as savePushNotificationSettings } from 'themes/glitch/actions/push_notifications';
-import { openModal } from 'themes/glitch/actions/modal';
+import { changeSetting, saveSettings } from 'flavours/glitch/actions/settings';
+import { clearNotifications } from 'flavours/glitch/actions/notifications';
+import { changeAlerts as changePushNotifications, saveSettings as savePushNotificationSettings } from 'flavours/glitch/actions/push_notifications';
+import { openModal } from 'flavours/glitch/actions/modal';
const messages = defineMessages({
clearMessage: { id: 'notifications.clear_confirmation', defaultMessage: 'Are you sure you want to permanently clear all your notifications?' },
diff --git a/app/javascript/themes/glitch/features/notifications/containers/notification_container.js b/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js
similarity index 83%
rename from app/javascript/themes/glitch/features/notifications/containers/notification_container.js
rename to app/javascript/flavours/glitch/features/notifications/containers/notification_container.js
index 033c61e3d89..be007f30bb0 100644
--- a/app/javascript/themes/glitch/features/notifications/containers/notification_container.js
+++ b/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js
@@ -2,9 +2,9 @@
import { connect } from 'react-redux';
// Our imports.
-import { makeGetNotification } from 'themes/glitch/selectors';
+import { makeGetNotification } from 'flavours/glitch/selectors';
import Notification from '../components/notification';
-import { mentionCompose } from 'themes/glitch/actions/compose';
+import { mentionCompose } from 'flavours/glitch/actions/compose';
const makeMapStateToProps = () => {
const getNotification = makeGetNotification();
diff --git a/app/javascript/themes/glitch/features/notifications/containers/overlay_container.js b/app/javascript/flavours/glitch/features/notifications/containers/overlay_container.js
similarity index 84%
rename from app/javascript/themes/glitch/features/notifications/containers/overlay_container.js
rename to app/javascript/flavours/glitch/features/notifications/containers/overlay_container.js
index 52649cdd755..ee2d19814a5 100644
--- a/app/javascript/themes/glitch/features/notifications/containers/overlay_container.js
+++ b/app/javascript/flavours/glitch/features/notifications/containers/overlay_container.js
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
// Our imports.
import NotificationOverlay from '../components/overlay';
-import { markNotificationForDelete } from 'themes/glitch/actions/notifications';
+import { markNotificationForDelete } from 'flavours/glitch/actions/notifications';
const mapDispatchToProps = dispatch => ({
onMarkForDelete(id, yes) {
diff --git a/app/javascript/themes/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js
similarity index 94%
rename from app/javascript/themes/glitch/features/notifications/index.js
rename to app/javascript/flavours/glitch/features/notifications/index.js
index 1ecde660a80..12b0b5b834d 100644
--- a/app/javascript/themes/glitch/features/notifications/index.js
+++ b/app/javascript/flavours/glitch/features/notifications/index.js
@@ -2,21 +2,21 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
import {
enterNotificationClearingMode,
expandNotifications,
scrollTopNotifications,
-} from 'themes/glitch/actions/notifications';
-import { addColumn, removeColumn, moveColumn } from 'themes/glitch/actions/columns';
+} from 'flavours/glitch/actions/notifications';
+import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
import NotificationContainer from './containers/notification_container';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnSettingsContainer from './containers/column_settings_container';
import { createSelector } from 'reselect';
import { List as ImmutableList } from 'immutable';
import { debounce } from 'lodash';
-import ScrollableList from 'themes/glitch/components/scrollable_list';
+import ScrollableList from 'flavours/glitch/components/scrollable_list';
const messages = defineMessages({
title: { id: 'column.notifications', defaultMessage: 'Notifications' },
diff --git a/app/javascript/themes/glitch/features/pinned_statuses/index.js b/app/javascript/flavours/glitch/features/pinned_statuses/index.js
similarity index 82%
rename from app/javascript/themes/glitch/features/pinned_statuses/index.js
rename to app/javascript/flavours/glitch/features/pinned_statuses/index.js
index 0a3997850ba..f56d701760c 100644
--- a/app/javascript/themes/glitch/features/pinned_statuses/index.js
+++ b/app/javascript/flavours/glitch/features/pinned_statuses/index.js
@@ -2,10 +2,10 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { fetchPinnedStatuses } from 'themes/glitch/actions/pin_statuses';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnBackButtonSlim from 'themes/glitch/components/column_back_button_slim';
-import StatusList from 'themes/glitch/components/status_list';
+import { fetchPinnedStatuses } from 'flavours/glitch/actions/pin_statuses';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
+import StatusList from 'flavours/glitch/components/status_list';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/themes/glitch/features/public_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js
similarity index 67%
rename from app/javascript/themes/glitch/features/public_timeline/containers/column_settings_container.js
rename to app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js
index 0185a7724cc..b13e2064533 100644
--- a/app/javascript/themes/glitch/features/public_timeline/containers/column_settings_container.js
+++ b/app/javascript/flavours/glitch/features/public_timeline/containers/column_settings_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
-import ColumnSettings from 'themes/glitch/features/community_timeline/components/column_settings';
-import { changeSetting } from 'themes/glitch/actions/settings';
+import ColumnSettings from 'flavours/glitch/features/community_timeline/components/column_settings';
+import { changeSetting } from 'flavours/glitch/actions/settings';
const mapStateToProps = state => ({
settings: state.getIn(['settings', 'public']),
diff --git a/app/javascript/themes/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js
similarity index 85%
rename from app/javascript/themes/glitch/features/public_timeline/index.js
rename to app/javascript/flavours/glitch/features/public_timeline/index.js
index f5b3865afa3..bbdd4612e1e 100644
--- a/app/javascript/themes/glitch/features/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/public_timeline/index.js
@@ -1,17 +1,17 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import StatusListContainer from 'themes/glitch/features/ui/containers/status_list_container';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
import {
refreshPublicTimeline,
expandPublicTimeline,
-} from 'themes/glitch/actions/timelines';
-import { addColumn, removeColumn, moveColumn } from 'themes/glitch/actions/columns';
+} from 'flavours/glitch/actions/timelines';
+import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnSettingsContainer from './containers/column_settings_container';
-import { connectPublicStream } from 'themes/glitch/actions/streaming';
+import { connectPublicStream } from 'flavours/glitch/actions/streaming';
const messages = defineMessages({
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
diff --git a/app/javascript/themes/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js
similarity index 79%
rename from app/javascript/themes/glitch/features/reblogs/index.js
rename to app/javascript/flavours/glitch/features/reblogs/index.js
index 8723f7c7cec..25b792b3979 100644
--- a/app/javascript/themes/glitch/features/reblogs/index.js
+++ b/app/javascript/flavours/glitch/features/reblogs/index.js
@@ -2,12 +2,12 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
-import { fetchReblogs } from 'themes/glitch/actions/interactions';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
+import { fetchReblogs } from 'flavours/glitch/actions/interactions';
import { ScrollContainer } from 'react-router-scroll-4';
-import AccountContainer from 'themes/glitch/containers/account_container';
-import Column from 'themes/glitch/features/ui/components/column';
-import ColumnBackButton from 'themes/glitch/components/column_back_button';
+import AccountContainer from 'flavours/glitch/containers/account_container';
+import Column from 'flavours/glitch/features/ui/components/column';
+import ColumnBackButton from 'flavours/glitch/components/column_back_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
const mapStateToProps = (state, props) => ({
diff --git a/app/javascript/themes/glitch/features/report/components/status_check_box.js b/app/javascript/flavours/glitch/features/report/components/status_check_box.js
similarity index 100%
rename from app/javascript/themes/glitch/features/report/components/status_check_box.js
rename to app/javascript/flavours/glitch/features/report/components/status_check_box.js
diff --git a/app/javascript/themes/glitch/features/report/containers/status_check_box_container.js b/app/javascript/flavours/glitch/features/report/containers/status_check_box_container.js
similarity index 88%
rename from app/javascript/themes/glitch/features/report/containers/status_check_box_container.js
rename to app/javascript/flavours/glitch/features/report/containers/status_check_box_container.js
index 40d55fb3c01..9bfd41ffc6d 100644
--- a/app/javascript/themes/glitch/features/report/containers/status_check_box_container.js
+++ b/app/javascript/flavours/glitch/features/report/containers/status_check_box_container.js
@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import StatusCheckBox from '../components/status_check_box';
-import { toggleStatusReport } from 'themes/glitch/actions/reports';
+import { toggleStatusReport } from 'flavours/glitch/actions/reports';
import { Set as ImmutableSet } from 'immutable';
const mapStateToProps = (state, { id }) => ({
diff --git a/app/javascript/flavours/glitch/features/standalone/compose/index.js b/app/javascript/flavours/glitch/features/standalone/compose/index.js
new file mode 100644
index 00000000000..b33c21cb5b6
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/standalone/compose/index.js
@@ -0,0 +1,20 @@
+import React from 'react';
+import ComposeFormContainer from 'flavours/glitch/features/compose/containers/compose_form_container';
+import NotificationsContainer from 'flavours/glitch/features/ui/containers/notifications_container';
+import LoadingBarContainer from 'flavours/glitch/features/ui/containers/loading_bar_container';
+import ModalContainer from 'flavours/glitch/features/ui/containers/modal_container';
+
+export default class Compose extends React.PureComponent {
+
+ render () {
+ return (
+
+
+
+
+
+
+ );
+ }
+
+}
diff --git a/app/javascript/themes/glitch/features/standalone/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
similarity index 84%
rename from app/javascript/themes/glitch/features/standalone/hashtag_timeline/index.js
rename to app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
index 7c56f264ff8..0ad2cef80eb 100644
--- a/app/javascript/themes/glitch/features/standalone/hashtag_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
@@ -1,13 +1,13 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import StatusListContainer from 'themes/glitch/features/ui/containers/status_list_container';
+import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
import {
refreshHashtagTimeline,
expandHashtagTimeline,
-} from 'themes/glitch/actions/timelines';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+} from 'flavours/glitch/actions/timelines';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
@connect()
export default class HashtagTimeline extends React.PureComponent {
diff --git a/app/javascript/themes/glitch/features/standalone/public_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
similarity index 85%
rename from app/javascript/themes/glitch/features/standalone/public_timeline/index.js
rename to app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
index b3fb5528840..717f6fcafc4 100644
--- a/app/javascript/themes/glitch/features/standalone/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
@@ -1,13 +1,13 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import StatusListContainer from 'themes/glitch/features/ui/containers/status_list_container';
+import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
import {
refreshPublicTimeline,
expandPublicTimeline,
-} from 'themes/glitch/actions/timelines';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+} from 'flavours/glitch/actions/timelines';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({
diff --git a/app/javascript/themes/glitch/features/status/components/action_bar.js b/app/javascript/flavours/glitch/features/status/components/action_bar.js
similarity index 95%
rename from app/javascript/themes/glitch/features/status/components/action_bar.js
rename to app/javascript/flavours/glitch/features/status/components/action_bar.js
index 6cda988d106..4d660ee3c0f 100644
--- a/app/javascript/themes/glitch/features/status/components/action_bar.js
+++ b/app/javascript/flavours/glitch/features/status/components/action_bar.js
@@ -1,10 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
-import IconButton from 'themes/glitch/components/icon_button';
+import IconButton from 'flavours/glitch/components/icon_button';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import DropdownMenuContainer from 'themes/glitch/containers/dropdown_menu_container';
+import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
diff --git a/app/javascript/themes/glitch/features/status/components/card.js b/app/javascript/flavours/glitch/features/status/components/card.js
similarity index 100%
rename from app/javascript/themes/glitch/features/status/components/card.js
rename to app/javascript/flavours/glitch/features/status/components/card.js
diff --git a/app/javascript/themes/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
similarity index 90%
rename from app/javascript/themes/glitch/features/status/components/detailed_status.js
rename to app/javascript/flavours/glitch/features/status/components/detailed_status.js
index df78ce4b6dd..0cb5238b0da 100644
--- a/app/javascript/themes/glitch/features/status/components/detailed_status.js
+++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
@@ -1,17 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import Avatar from 'themes/glitch/components/avatar';
-import DisplayName from 'themes/glitch/components/display_name';
-import StatusContent from 'themes/glitch/components/status_content';
-import StatusGallery from 'themes/glitch/components/media_gallery';
-import AttachmentList from 'themes/glitch/components/attachment_list';
+import Avatar from 'flavours/glitch/components/avatar';
+import DisplayName from 'flavours/glitch/components/display_name';
+import StatusContent from 'flavours/glitch/components/status_content';
+import StatusGallery from 'flavours/glitch/components/media_gallery';
+import AttachmentList from 'flavours/glitch/components/attachment_list';
import { Link } from 'react-router-dom';
import { FormattedDate, FormattedNumber } from 'react-intl';
import CardContainer from '../containers/card_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import Video from 'themes/glitch/features/video';
-import VisibilityIcon from 'themes/glitch/components/status_visibility_icon';
+import Video from 'flavours/glitch/features/video';
+import VisibilityIcon from 'flavours/glitch/components/status_visibility_icon';
export default class DetailedStatus extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/status/containers/card_container.js b/app/javascript/flavours/glitch/features/status/containers/card_container.js
similarity index 100%
rename from app/javascript/themes/glitch/features/status/containers/card_container.js
rename to app/javascript/flavours/glitch/features/status/containers/card_container.js
diff --git a/app/javascript/themes/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js
similarity index 91%
rename from app/javascript/themes/glitch/features/status/index.js
rename to app/javascript/flavours/glitch/features/status/index.js
index 8561bd4de74..93b0fe9d98e 100644
--- a/app/javascript/themes/glitch/features/status/index.js
+++ b/app/javascript/flavours/glitch/features/status/index.js
@@ -3,11 +3,11 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { fetchStatus } from 'themes/glitch/actions/statuses';
-import MissingIndicator from 'themes/glitch/components/missing_indicator';
+import { fetchStatus } from 'flavours/glitch/actions/statuses';
+import MissingIndicator from 'flavours/glitch/components/missing_indicator';
import DetailedStatus from './components/detailed_status';
import ActionBar from './components/action_bar';
-import Column from 'themes/glitch/features/ui/components/column';
+import Column from 'flavours/glitch/features/ui/components/column';
import {
favourite,
unfavourite,
@@ -15,23 +15,23 @@ import {
unreblog,
pin,
unpin,
-} from 'themes/glitch/actions/interactions';
+} from 'flavours/glitch/actions/interactions';
import {
replyCompose,
mentionCompose,
-} from 'themes/glitch/actions/compose';
-import { deleteStatus } from 'themes/glitch/actions/statuses';
-import { initReport } from 'themes/glitch/actions/reports';
-import { makeGetStatus } from 'themes/glitch/selectors';
+} from 'flavours/glitch/actions/compose';
+import { deleteStatus } from 'flavours/glitch/actions/statuses';
+import { initReport } from 'flavours/glitch/actions/reports';
+import { makeGetStatus } from 'flavours/glitch/selectors';
import { ScrollContainer } from 'react-router-scroll-4';
-import ColumnBackButton from 'themes/glitch/components/column_back_button';
-import StatusContainer from 'themes/glitch/containers/status_container';
-import { openModal } from 'themes/glitch/actions/modal';
+import ColumnBackButton from 'flavours/glitch/components/column_back_button';
+import StatusContainer from 'flavours/glitch/containers/status_container';
+import { openModal } from 'flavours/glitch/actions/modal';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { HotKeys } from 'react-hotkeys';
-import { boostModal, deleteModal } from 'themes/glitch/util/initial_state';
-import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'themes/glitch/util/fullscreen';
+import { boostModal, deleteModal } from 'flavours/glitch/util/initial_state';
+import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
diff --git a/app/javascript/themes/glitch/features/ui/components/actions_modal.js b/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
similarity index 86%
rename from app/javascript/themes/glitch/features/ui/components/actions_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/actions_modal.js
index 7a2b78b63d3..0873c282faf 100644
--- a/app/javascript/themes/glitch/features/ui/components/actions_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/actions_modal.js
@@ -2,11 +2,11 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import StatusContent from 'themes/glitch/components/status_content';
-import Avatar from 'themes/glitch/components/avatar';
-import RelativeTimestamp from 'themes/glitch/components/relative_timestamp';
-import DisplayName from 'themes/glitch/components/display_name';
-import IconButton from 'themes/glitch/components/icon_button';
+import StatusContent from 'flavours/glitch/components/status_content';
+import Avatar from 'flavours/glitch/components/avatar';
+import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
+import DisplayName from 'flavours/glitch/components/display_name';
+import IconButton from 'flavours/glitch/components/icon_button';
import classNames from 'classnames';
export default class ActionsModal extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/ui/components/boost_modal.js b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js
similarity index 88%
rename from app/javascript/themes/glitch/features/ui/components/boost_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/boost_modal.js
index 49781db10d0..9652bcb2db0 100644
--- a/app/javascript/themes/glitch/features/ui/components/boost_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/boost_modal.js
@@ -2,11 +2,11 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
-import Button from 'themes/glitch/components/button';
-import StatusContent from 'themes/glitch/components/status_content';
-import Avatar from 'themes/glitch/components/avatar';
-import RelativeTimestamp from 'themes/glitch/components/relative_timestamp';
-import DisplayName from 'themes/glitch/components/display_name';
+import Button from 'flavours/glitch/components/button';
+import StatusContent from 'flavours/glitch/components/status_content';
+import Avatar from 'flavours/glitch/components/avatar';
+import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
+import DisplayName from 'flavours/glitch/components/display_name';
import ImmutablePureComponent from 'react-immutable-pure-component';
const messages = defineMessages({
diff --git a/app/javascript/themes/glitch/features/ui/components/bundle.js b/app/javascript/flavours/glitch/features/ui/components/bundle.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/components/bundle.js
rename to app/javascript/flavours/glitch/features/ui/components/bundle.js
diff --git a/app/javascript/themes/glitch/features/ui/components/bundle_column_error.js b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js
similarity index 88%
rename from app/javascript/themes/glitch/features/ui/components/bundle_column_error.js
rename to app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js
index daedc629934..3e979a2506d 100644
--- a/app/javascript/themes/glitch/features/ui/components/bundle_column_error.js
+++ b/app/javascript/flavours/glitch/features/ui/components/bundle_column_error.js
@@ -4,8 +4,8 @@ import { defineMessages, injectIntl } from 'react-intl';
import Column from './column';
import ColumnHeader from './column_header';
-import ColumnBackButtonSlim from 'themes/glitch/components/column_back_button_slim';
-import IconButton from 'themes/glitch/components/icon_button';
+import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
+import IconButton from 'flavours/glitch/components/icon_button';
const messages = defineMessages({
title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' },
diff --git a/app/javascript/themes/glitch/features/ui/components/bundle_modal_error.js b/app/javascript/flavours/glitch/features/ui/components/bundle_modal_error.js
similarity index 95%
rename from app/javascript/themes/glitch/features/ui/components/bundle_modal_error.js
rename to app/javascript/flavours/glitch/features/ui/components/bundle_modal_error.js
index 8cca32ae9a6..2c14a1e5c3a 100644
--- a/app/javascript/themes/glitch/features/ui/components/bundle_modal_error.js
+++ b/app/javascript/flavours/glitch/features/ui/components/bundle_modal_error.js
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
-import IconButton from 'themes/glitch/components/icon_button';
+import IconButton from 'flavours/glitch/components/icon_button';
const messages = defineMessages({
error: { id: 'bundle_modal_error.message', defaultMessage: 'Something went wrong while loading this component.' },
diff --git a/app/javascript/themes/glitch/features/ui/components/column.js b/app/javascript/flavours/glitch/features/ui/components/column.js
similarity index 93%
rename from app/javascript/themes/glitch/features/ui/components/column.js
rename to app/javascript/flavours/glitch/features/ui/components/column.js
index 73a5bc15e5e..ab78414e056 100644
--- a/app/javascript/themes/glitch/features/ui/components/column.js
+++ b/app/javascript/flavours/glitch/features/ui/components/column.js
@@ -2,8 +2,8 @@ import React from 'react';
import ColumnHeader from './column_header';
import PropTypes from 'prop-types';
import { debounce } from 'lodash';
-import { scrollTop } from 'themes/glitch/util/scroll';
-import { isMobile } from 'themes/glitch/util/is_mobile';
+import { scrollTop } from 'flavours/glitch/util/scroll';
+import { isMobile } from 'flavours/glitch/util/is_mobile';
export default class Column extends React.PureComponent {
diff --git a/app/javascript/themes/glitch/features/ui/components/column_header.js b/app/javascript/flavours/glitch/features/ui/components/column_header.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/components/column_header.js
rename to app/javascript/flavours/glitch/features/ui/components/column_header.js
diff --git a/app/javascript/themes/glitch/features/ui/components/column_link.js b/app/javascript/flavours/glitch/features/ui/components/column_link.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/components/column_link.js
rename to app/javascript/flavours/glitch/features/ui/components/column_link.js
diff --git a/app/javascript/themes/glitch/features/ui/components/column_loading.js b/app/javascript/flavours/glitch/features/ui/components/column_loading.js
similarity index 83%
rename from app/javascript/themes/glitch/features/ui/components/column_loading.js
rename to app/javascript/flavours/glitch/features/ui/components/column_loading.js
index 75f26218ad0..ba2d0824efe 100644
--- a/app/javascript/themes/glitch/features/ui/components/column_loading.js
+++ b/app/javascript/flavours/glitch/features/ui/components/column_loading.js
@@ -1,8 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Column from 'themes/glitch/components/column';
-import ColumnHeader from 'themes/glitch/components/column_header';
+import Column from 'flavours/glitch/components/column';
+import ColumnHeader from 'flavours/glitch/components/column_header';
import ImmutablePureComponent from 'react-immutable-pure-component';
export default class ColumnLoading extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/ui/components/column_subheading.js b/app/javascript/flavours/glitch/features/ui/components/column_subheading.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/components/column_subheading.js
rename to app/javascript/flavours/glitch/features/ui/components/column_subheading.js
diff --git a/app/javascript/themes/glitch/features/ui/components/columns_area.js b/app/javascript/flavours/glitch/features/ui/components/columns_area.js
similarity index 98%
rename from app/javascript/themes/glitch/features/ui/components/columns_area.js
rename to app/javascript/flavours/glitch/features/ui/components/columns_area.js
index 4529503633b..264f60724da 100644
--- a/app/javascript/themes/glitch/features/ui/components/columns_area.js
+++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.js
@@ -11,10 +11,10 @@ import BundleContainer from '../containers/bundle_container';
import ColumnLoading from './column_loading';
import DrawerLoading from './drawer_loading';
import BundleColumnError from './bundle_column_error';
-import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses } from 'themes/glitch/util/async-components';
+import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses } from 'flavours/glitch/util/async-components';
import detectPassiveEvents from 'detect-passive-events';
-import { scrollRight } from 'themes/glitch/util/scroll';
+import { scrollRight } from 'flavours/glitch/util/scroll';
const componentMap = {
'COMPOSE': Compose,
diff --git a/app/javascript/themes/glitch/features/ui/components/confirmation_modal.js b/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js
similarity index 95%
rename from app/javascript/themes/glitch/features/ui/components/confirmation_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js
index 3d568aec37e..d4d1e587ee2 100644
--- a/app/javascript/themes/glitch/features/ui/components/confirmation_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/confirmation_modal.js
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage } from 'react-intl';
-import Button from 'themes/glitch/components/button';
+import Button from 'flavours/glitch/components/button';
@injectIntl
export default class ConfirmationModal extends React.PureComponent {
diff --git a/app/javascript/themes/glitch/features/ui/components/doodle_modal.js b/app/javascript/flavours/glitch/features/ui/components/doodle_modal.js
similarity index 98%
rename from app/javascript/themes/glitch/features/ui/components/doodle_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/doodle_modal.js
index 819656dbf23..9c74451b3ea 100644
--- a/app/javascript/themes/glitch/features/ui/components/doodle_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/doodle_modal.js
@@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Button from 'themes/glitch/components/button';
+import Button from 'flavours/glitch/components/button';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Atrament from 'atrament'; // the doodling library
import { connect } from 'react-redux';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { doodleSet, uploadCompose } from 'themes/glitch/actions/compose';
-import IconButton from 'themes/glitch/components/icon_button';
+import { doodleSet, uploadCompose } from 'flavours/glitch/actions/compose';
+import IconButton from 'flavours/glitch/components/icon_button';
import { debounce, mapValues } from 'lodash';
import classNames from 'classnames';
diff --git a/app/javascript/themes/glitch/features/ui/components/drawer_loading.js b/app/javascript/flavours/glitch/features/ui/components/drawer_loading.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/components/drawer_loading.js
rename to app/javascript/flavours/glitch/features/ui/components/drawer_loading.js
diff --git a/app/javascript/themes/glitch/features/ui/components/embed_modal.js b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/components/embed_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/embed_modal.js
diff --git a/app/javascript/themes/glitch/features/ui/components/image_loader.js b/app/javascript/flavours/glitch/features/ui/components/image_loader.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/components/image_loader.js
rename to app/javascript/flavours/glitch/features/ui/components/image_loader.js
diff --git a/app/javascript/themes/glitch/features/ui/components/media_modal.js b/app/javascript/flavours/glitch/features/ui/components/media_modal.js
similarity index 96%
rename from app/javascript/themes/glitch/features/ui/components/media_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/media_modal.js
index 1dad972b2e3..e56147c5bcb 100644
--- a/app/javascript/themes/glitch/features/ui/components/media_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.js
@@ -2,9 +2,9 @@ import React from 'react';
import ReactSwipeableViews from 'react-swipeable-views';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import ExtendedVideoPlayer from 'themes/glitch/components/extended_video_player';
+import ExtendedVideoPlayer from 'flavours/glitch/components/extended_video_player';
import { defineMessages, injectIntl } from 'react-intl';
-import IconButton from 'themes/glitch/components/icon_button';
+import IconButton from 'flavours/glitch/components/icon_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImageLoader from './image_loader';
diff --git a/app/javascript/themes/glitch/features/ui/components/modal_loading.js b/app/javascript/flavours/glitch/features/ui/components/modal_loading.js
similarity index 86%
rename from app/javascript/themes/glitch/features/ui/components/modal_loading.js
rename to app/javascript/flavours/glitch/features/ui/components/modal_loading.js
index e14d20fbb2f..b1c32215414 100644
--- a/app/javascript/themes/glitch/features/ui/components/modal_loading.js
+++ b/app/javascript/flavours/glitch/features/ui/components/modal_loading.js
@@ -1,6 +1,6 @@
import React from 'react';
-import LoadingIndicator from 'themes/glitch/components/loading_indicator';
+import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
// Keep the markup in sync with
// (make sure they have the same dimensions)
diff --git a/app/javascript/themes/glitch/features/ui/components/modal_root.js b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
similarity index 98%
rename from app/javascript/themes/glitch/features/ui/components/modal_root.js
rename to app/javascript/flavours/glitch/features/ui/components/modal_root.js
index fbe7941708d..61b2392839d 100644
--- a/app/javascript/themes/glitch/features/ui/components/modal_root.js
+++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.js
@@ -15,7 +15,7 @@ import {
ReportModal,
SettingsModal,
EmbedModal,
-} from 'themes/glitch/util/async-components';
+} from 'flavours/glitch/util/async-components';
const MODAL_COMPONENTS = {
'MEDIA': () => Promise.resolve({ default: MediaModal }),
diff --git a/app/javascript/themes/glitch/features/ui/components/mute_modal.js b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
similarity index 91%
rename from app/javascript/themes/glitch/features/ui/components/mute_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/mute_modal.js
index ffccdc84d36..0202b1ab13e 100644
--- a/app/javascript/themes/glitch/features/ui/components/mute_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/mute_modal.js
@@ -3,10 +3,10 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage } from 'react-intl';
import Toggle from 'react-toggle';
-import Button from 'themes/glitch/components/button';
-import { closeModal } from 'themes/glitch/actions/modal';
-import { muteAccount } from 'themes/glitch/actions/accounts';
-import { toggleHideNotifications } from 'themes/glitch/actions/mutes';
+import Button from 'flavours/glitch/components/button';
+import { closeModal } from 'flavours/glitch/actions/modal';
+import { muteAccount } from 'flavours/glitch/actions/accounts';
+import { toggleHideNotifications } from 'flavours/glitch/actions/mutes';
const mapStateToProps = state => {
diff --git a/app/javascript/themes/glitch/features/ui/components/onboarding_modal.js b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
similarity index 97%
rename from app/javascript/themes/glitch/features/ui/components/onboarding_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
index 58875262ef7..21f1addea5e 100644
--- a/app/javascript/themes/glitch/features/ui/components/onboarding_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/onboarding_modal.js
@@ -5,16 +5,16 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ReactSwipeableViews from 'react-swipeable-views';
import classNames from 'classnames';
-import Permalink from 'themes/glitch/components/permalink';
-import ComposeForm from 'themes/glitch/features/compose/components/compose_form';
-import Search from 'themes/glitch/features/compose/components/search';
-import NavigationBar from 'themes/glitch/features/compose/components/navigation_bar';
+import Permalink from 'flavours/glitch/components/permalink';
+import ComposeForm from 'flavours/glitch/features/compose/components/compose_form';
+import Search from 'flavours/glitch/features/compose/components/search';
+import NavigationBar from 'flavours/glitch/features/compose/components/navigation_bar';
import ColumnHeader from './column_header';
import {
List as ImmutableList,
Map as ImmutableMap,
} from 'immutable';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const noop = () => { };
diff --git a/app/javascript/themes/glitch/features/ui/components/report_modal.js b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
similarity index 89%
rename from app/javascript/themes/glitch/features/ui/components/report_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/report_modal.js
index e6153948ece..b4dc1e3d61f 100644
--- a/app/javascript/themes/glitch/features/ui/components/report_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
@@ -1,15 +1,15 @@
import React from 'react';
import { connect } from 'react-redux';
-import { changeReportComment, submitReport } from 'themes/glitch/actions/reports';
-import { refreshAccountTimeline } from 'themes/glitch/actions/timelines';
+import { changeReportComment, submitReport } from 'flavours/glitch/actions/reports';
+import { refreshAccountTimeline } from 'flavours/glitch/actions/timelines';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
-import { makeGetAccount } from 'themes/glitch/selectors';
+import { makeGetAccount } from 'flavours/glitch/selectors';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
-import StatusCheckBox from 'themes/glitch/features/report/containers/status_check_box_container';
+import StatusCheckBox from 'flavours/glitch/features/report/containers/status_check_box_container';
import { OrderedSet } from 'immutable';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import Button from 'themes/glitch/components/button';
+import Button from 'flavours/glitch/components/button';
const messages = defineMessages({
placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' },
diff --git a/app/javascript/themes/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
similarity index 98%
rename from app/javascript/themes/glitch/features/ui/components/tabs_bar.js
rename to app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
index ef5deae992d..89b455dd879 100644
--- a/app/javascript/themes/glitch/features/ui/components/tabs_bar.js
+++ b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { NavLink } from 'react-router-dom';
import { FormattedMessage, injectIntl } from 'react-intl';
import { debounce } from 'lodash';
-import { isUserTouching } from 'themes/glitch/util/is_mobile';
+import { isUserTouching } from 'flavours/glitch/util/is_mobile';
export const links = [
,
diff --git a/app/javascript/themes/glitch/features/ui/components/upload_area.js b/app/javascript/flavours/glitch/features/ui/components/upload_area.js
similarity index 96%
rename from app/javascript/themes/glitch/features/ui/components/upload_area.js
rename to app/javascript/flavours/glitch/features/ui/components/upload_area.js
index 72a450215c5..cc6b6d17136 100644
--- a/app/javascript/themes/glitch/features/ui/components/upload_area.js
+++ b/app/javascript/flavours/glitch/features/ui/components/upload_area.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import Motion from 'themes/glitch/util/optional_motion';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
import { FormattedMessage } from 'react-intl';
diff --git a/app/javascript/themes/glitch/features/ui/components/video_modal.js b/app/javascript/flavours/glitch/features/ui/components/video_modal.js
similarity index 94%
rename from app/javascript/themes/glitch/features/ui/components/video_modal.js
rename to app/javascript/flavours/glitch/features/ui/components/video_modal.js
index 91168c79079..22fa998fb36 100644
--- a/app/javascript/themes/glitch/features/ui/components/video_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/video_modal.js
@@ -1,7 +1,7 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import Video from 'themes/glitch/features/video';
+import Video from 'flavours/glitch/features/video';
import ImmutablePureComponent from 'react-immutable-pure-component';
export default class VideoModal extends ImmutablePureComponent {
diff --git a/app/javascript/themes/glitch/features/ui/containers/bundle_container.js b/app/javascript/flavours/glitch/features/ui/containers/bundle_container.js
similarity index 91%
rename from app/javascript/themes/glitch/features/ui/containers/bundle_container.js
rename to app/javascript/flavours/glitch/features/ui/containers/bundle_container.js
index e6f9afcf714..c9086c9bca1 100644
--- a/app/javascript/themes/glitch/features/ui/containers/bundle_container.js
+++ b/app/javascript/flavours/glitch/features/ui/containers/bundle_container.js
@@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import Bundle from '../components/bundle';
-import { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from 'themes/glitch/actions/bundles';
+import { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from 'flavours/glitch/actions/bundles';
const mapDispatchToProps = dispatch => ({
onFetch () {
diff --git a/app/javascript/themes/glitch/features/ui/containers/columns_area_container.js b/app/javascript/flavours/glitch/features/ui/containers/columns_area_container.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/containers/columns_area_container.js
rename to app/javascript/flavours/glitch/features/ui/containers/columns_area_container.js
diff --git a/app/javascript/themes/glitch/features/ui/containers/loading_bar_container.js b/app/javascript/flavours/glitch/features/ui/containers/loading_bar_container.js
similarity index 100%
rename from app/javascript/themes/glitch/features/ui/containers/loading_bar_container.js
rename to app/javascript/flavours/glitch/features/ui/containers/loading_bar_container.js
diff --git a/app/javascript/themes/glitch/features/ui/containers/modal_container.js b/app/javascript/flavours/glitch/features/ui/containers/modal_container.js
similarity index 86%
rename from app/javascript/themes/glitch/features/ui/containers/modal_container.js
rename to app/javascript/flavours/glitch/features/ui/containers/modal_container.js
index c26f19886b8..f074002e44e 100644
--- a/app/javascript/themes/glitch/features/ui/containers/modal_container.js
+++ b/app/javascript/flavours/glitch/features/ui/containers/modal_container.js
@@ -1,5 +1,5 @@
import { connect } from 'react-redux';
-import { closeModal } from 'themes/glitch/actions/modal';
+import { closeModal } from 'flavours/glitch/actions/modal';
import ModalRoot from '../components/modal_root';
const mapStateToProps = state => ({
diff --git a/app/javascript/themes/glitch/features/ui/containers/notifications_container.js b/app/javascript/flavours/glitch/features/ui/containers/notifications_container.js
similarity index 76%
rename from app/javascript/themes/glitch/features/ui/containers/notifications_container.js
rename to app/javascript/flavours/glitch/features/ui/containers/notifications_container.js
index 5bd4017f5f8..88d482bcf2e 100644
--- a/app/javascript/themes/glitch/features/ui/containers/notifications_container.js
+++ b/app/javascript/flavours/glitch/features/ui/containers/notifications_container.js
@@ -1,7 +1,7 @@
import { connect } from 'react-redux';
import { NotificationStack } from 'react-notification';
-import { dismissAlert } from 'themes/glitch/actions/alerts';
-import { getAlerts } from 'themes/glitch/selectors';
+import { dismissAlert } from 'flavours/glitch/actions/alerts';
+import { getAlerts } from 'flavours/glitch/selectors';
const mapStateToProps = state => ({
notifications: getAlerts(state),
diff --git a/app/javascript/themes/glitch/features/ui/containers/status_list_container.js b/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
similarity index 92%
rename from app/javascript/themes/glitch/features/ui/containers/status_list_container.js
rename to app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
index 807c82e16b5..69508f9ff5d 100644
--- a/app/javascript/themes/glitch/features/ui/containers/status_list_container.js
+++ b/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
@@ -1,10 +1,10 @@
import { connect } from 'react-redux';
-import StatusList from 'themes/glitch/components/status_list';
-import { scrollTopTimeline } from 'themes/glitch/actions/timelines';
+import StatusList from 'flavours/glitch/components/status_list';
+import { scrollTopTimeline } from 'flavours/glitch/actions/timelines';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import { createSelector } from 'reselect';
import { debounce } from 'lodash';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
const makeGetStatusIds = () => createSelector([
(state, { type }) => state.getIn(['settings', type], ImmutableMap()),
diff --git a/app/javascript/themes/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js
similarity index 96%
rename from app/javascript/themes/glitch/features/ui/index.js
rename to app/javascript/flavours/glitch/features/ui/index.js
index 3eea63189f0..4a19829164b 100644
--- a/app/javascript/themes/glitch/features/ui/index.js
+++ b/app/javascript/flavours/glitch/features/ui/index.js
@@ -6,13 +6,13 @@ import TabsBar from './components/tabs_bar';
import ModalContainer from './containers/modal_container';
import { connect } from 'react-redux';
import { Redirect, withRouter } from 'react-router-dom';
-import { isMobile } from 'themes/glitch/util/is_mobile';
+import { isMobile } from 'flavours/glitch/util/is_mobile';
import { debounce } from 'lodash';
-import { uploadCompose, resetCompose } from 'themes/glitch/actions/compose';
-import { refreshHomeTimeline } from 'themes/glitch/actions/timelines';
-import { refreshNotifications } from 'themes/glitch/actions/notifications';
-import { clearHeight } from 'themes/glitch/actions/height_cache';
-import { WrappedSwitch, WrappedRoute } from 'themes/glitch/util/react_router_helpers';
+import { uploadCompose, resetCompose } from 'flavours/glitch/actions/compose';
+import { refreshHomeTimeline } from 'flavours/glitch/actions/timelines';
+import { refreshNotifications } from 'flavours/glitch/actions/notifications';
+import { clearHeight } from 'flavours/glitch/actions/height_cache';
+import { WrappedSwitch, WrappedRoute } from 'flavours/glitch/util/react_router_helpers';
import UploadArea from './components/upload_area';
import ColumnsAreaContainer from './containers/columns_area_container';
import classNames from 'classnames';
@@ -38,9 +38,9 @@ import {
Blocks,
Mutes,
PinnedStatuses,
-} from 'themes/glitch/util/async-components';
+} from 'flavours/glitch/util/async-components';
import { HotKeys } from 'react-hotkeys';
-import { me } from 'themes/glitch/util/initial_state';
+import { me } from 'flavours/glitch/util/initial_state';
import { defineMessages, injectIntl } from 'react-intl';
// Dummy import, to make sure that ends up in the application bundle.
diff --git a/app/javascript/themes/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js
similarity index 99%
rename from app/javascript/themes/glitch/features/video/index.js
rename to app/javascript/flavours/glitch/features/video/index.js
index 0ecbe37c9d6..97c1c27fab7 100644
--- a/app/javascript/themes/glitch/features/video/index.js
+++ b/app/javascript/flavours/glitch/features/video/index.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { throttle } from 'lodash';
import classNames from 'classnames';
-import { isFullscreen, requestFullscreen, exitFullscreen } from 'themes/glitch/util/fullscreen';
+import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen';
const messages = defineMessages({
play: { id: 'video.play', defaultMessage: 'Play' },
diff --git a/app/javascript/themes/glitch/middleware/errors.js b/app/javascript/flavours/glitch/middleware/errors.js
similarity index 92%
rename from app/javascript/themes/glitch/middleware/errors.js
rename to app/javascript/flavours/glitch/middleware/errors.js
index c54e7b0a281..f3dfc8b069e 100644
--- a/app/javascript/themes/glitch/middleware/errors.js
+++ b/app/javascript/flavours/glitch/middleware/errors.js
@@ -1,4 +1,4 @@
-import { showAlert } from 'themes/glitch/actions/alerts';
+import { showAlert } from 'flavours/glitch/actions/alerts';
const defaultFailSuffix = 'FAIL';
diff --git a/app/javascript/themes/glitch/middleware/loading_bar.js b/app/javascript/flavours/glitch/middleware/loading_bar.js
similarity index 100%
rename from app/javascript/themes/glitch/middleware/loading_bar.js
rename to app/javascript/flavours/glitch/middleware/loading_bar.js
diff --git a/app/javascript/themes/glitch/middleware/sounds.js b/app/javascript/flavours/glitch/middleware/sounds.js
similarity index 100%
rename from app/javascript/themes/glitch/middleware/sounds.js
rename to app/javascript/flavours/glitch/middleware/sounds.js
diff --git a/app/javascript/flavours/glitch/packs/about.js b/app/javascript/flavours/glitch/packs/about.js
new file mode 100644
index 00000000000..bc0a4887bb1
--- /dev/null
+++ b/app/javascript/flavours/glitch/packs/about.js
@@ -0,0 +1,22 @@
+import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+
+function loaded() {
+ const TimelineContainer = require('flavours/glitch/containers/timeline_container').default;
+ const React = require('react');
+ const ReactDOM = require('react-dom');
+ const mountNode = document.getElementById('mastodon-timeline');
+
+ if (mountNode !== null) {
+ const props = JSON.parse(mountNode.getAttribute('data-props'));
+ ReactDOM.render(, mountNode);
+ }
+}
+
+function main() {
+ const ready = require('flavours/glitch/util/ready').default;
+ ready(loaded);
+}
+
+loadPolyfills().then(main).catch(error => {
+ console.error(error);
+});
diff --git a/app/javascript/flavours/glitch/packs/common.js b/app/javascript/flavours/glitch/packs/common.js
new file mode 100644
index 00000000000..07445d2b3ff
--- /dev/null
+++ b/app/javascript/flavours/glitch/packs/common.js
@@ -0,0 +1 @@
+import 'flavours/glitch/styles/index.scss';
diff --git a/app/javascript/flavours/glitch/packs/home.js b/app/javascript/flavours/glitch/packs/home.js
new file mode 100644
index 00000000000..b8f7b7d8efd
--- /dev/null
+++ b/app/javascript/flavours/glitch/packs/home.js
@@ -0,0 +1,7 @@
+import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+
+loadPolyfills().then(() => {
+ require('flavours/glitch/util/main').default();
+}).catch(e => {
+ console.error(e);
+});
diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js
new file mode 100644
index 00000000000..9ea82b53aa2
--- /dev/null
+++ b/app/javascript/flavours/glitch/packs/public.js
@@ -0,0 +1,75 @@
+import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+import ready from 'flavours/glitch/util/ready';
+
+function main() {
+ const IntlRelativeFormat = require('intl-relativeformat').default;
+ const emojify = require('flavours/glitch/util/emoji').default;
+ const { getLocale } = require('locales');
+ const { localeData } = getLocale();
+ const VideoContainer = require('flavours/glitch/containers/video_container').default;
+ const MediaGalleryContainer = require('flavours/glitch/containers/media_gallery_container').default;
+ const CardContainer = require('flavours/glitch/containers/card_container').default;
+ const React = require('react');
+ const ReactDOM = require('react-dom');
+
+ localeData.forEach(IntlRelativeFormat.__addLocaleData);
+
+ ready(() => {
+ const locale = document.documentElement.lang;
+
+ const dateTimeFormat = new Intl.DateTimeFormat(locale, {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ });
+
+ const relativeFormat = new IntlRelativeFormat(locale);
+
+ [].forEach.call(document.querySelectorAll('.emojify'), (content) => {
+ content.innerHTML = emojify(content.innerHTML);
+ });
+
+ [].forEach.call(document.querySelectorAll('time.formatted'), (content) => {
+ const datetime = new Date(content.getAttribute('datetime'));
+ const formattedDate = dateTimeFormat.format(datetime);
+
+ content.title = formattedDate;
+ content.textContent = formattedDate;
+ });
+
+ [].forEach.call(document.querySelectorAll('time.time-ago'), (content) => {
+ const datetime = new Date(content.getAttribute('datetime'));
+
+ content.title = dateTimeFormat.format(datetime);
+ content.textContent = relativeFormat.format(datetime);
+ });
+
+ [].forEach.call(document.querySelectorAll('.logo-button'), (content) => {
+ content.addEventListener('click', (e) => {
+ e.preventDefault();
+ window.open(e.target.href, 'mastodon-intent', 'width=400,height=400,resizable=no,menubar=no,status=no,scrollbars=yes');
+ });
+ });
+
+ [].forEach.call(document.querySelectorAll('[data-component="Video"]'), (content) => {
+ const props = JSON.parse(content.getAttribute('data-props'));
+ ReactDOM.render(, content);
+ });
+
+ [].forEach.call(document.querySelectorAll('[data-component="MediaGallery"]'), (content) => {
+ const props = JSON.parse(content.getAttribute('data-props'));
+ ReactDOM.render(, content);
+ });
+
+ [].forEach.call(document.querySelectorAll('[data-component="Card"]'), (content) => {
+ const props = JSON.parse(content.getAttribute('data-props'));
+ ReactDOM.render(, content);
+ });
+ });
+}
+
+loadPolyfills().then(main).catch(error => {
+ console.error(error);
+});
diff --git a/app/javascript/flavours/glitch/packs/share.js b/app/javascript/flavours/glitch/packs/share.js
new file mode 100644
index 00000000000..9f2aa255397
--- /dev/null
+++ b/app/javascript/flavours/glitch/packs/share.js
@@ -0,0 +1,22 @@
+import loadPolyfills from 'flavours/glitch/util/load_polyfills';
+
+function loaded() {
+ const ComposeContainer = require('flavours/glitch/containers/compose_container').default;
+ const React = require('react');
+ const ReactDOM = require('react-dom');
+ const mountNode = document.getElementById('mastodon-compose');
+
+ if (mountNode !== null) {
+ const props = JSON.parse(mountNode.getAttribute('data-props'));
+ ReactDOM.render(, mountNode);
+ }
+}
+
+function main() {
+ const ready = require('flavours/glitch/util/ready').default;
+ ready(loaded);
+}
+
+loadPolyfills().then(main).catch(error => {
+ console.error(error);
+});
diff --git a/app/javascript/themes/glitch/reducers/accounts.js b/app/javascript/flavours/glitch/reducers/accounts.js
similarity index 85%
rename from app/javascript/themes/glitch/reducers/accounts.js
rename to app/javascript/flavours/glitch/reducers/accounts.js
index 0a65d3723c9..5113a281aa5 100644
--- a/app/javascript/themes/glitch/reducers/accounts.js
+++ b/app/javascript/flavours/glitch/reducers/accounts.js
@@ -6,16 +6,16 @@ import {
FOLLOWING_EXPAND_SUCCESS,
FOLLOW_REQUESTS_FETCH_SUCCESS,
FOLLOW_REQUESTS_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import {
BLOCKS_FETCH_SUCCESS,
BLOCKS_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/blocks';
+} from 'flavours/glitch/actions/blocks';
import {
MUTES_FETCH_SUCCESS,
MUTES_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/mutes';
-import { COMPOSE_SUGGESTIONS_READY } from 'themes/glitch/actions/compose';
+} from 'flavours/glitch/actions/mutes';
+import { COMPOSE_SUGGESTIONS_READY } from 'flavours/glitch/actions/compose';
import {
REBLOG_SUCCESS,
UNREBLOG_SUCCESS,
@@ -23,28 +23,28 @@ import {
UNFAVOURITE_SUCCESS,
REBLOGS_FETCH_SUCCESS,
FAVOURITES_FETCH_SUCCESS,
-} from 'themes/glitch/actions/interactions';
+} from 'flavours/glitch/actions/interactions';
import {
TIMELINE_REFRESH_SUCCESS,
TIMELINE_UPDATE,
TIMELINE_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/timelines';
+} from 'flavours/glitch/actions/timelines';
import {
STATUS_FETCH_SUCCESS,
CONTEXT_FETCH_SUCCESS,
-} from 'themes/glitch/actions/statuses';
-import { SEARCH_FETCH_SUCCESS } from 'themes/glitch/actions/search';
+} from 'flavours/glitch/actions/statuses';
+import { SEARCH_FETCH_SUCCESS } from 'flavours/glitch/actions/search';
import {
NOTIFICATIONS_UPDATE,
NOTIFICATIONS_REFRESH_SUCCESS,
NOTIFICATIONS_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/notifications';
+} from 'flavours/glitch/actions/notifications';
import {
FAVOURITED_STATUSES_FETCH_SUCCESS,
FAVOURITED_STATUSES_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/favourites';
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
-import emojify from 'themes/glitch/util/emoji';
+} from 'flavours/glitch/actions/favourites';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
+import emojify from 'flavours/glitch/util/emoji';
import { Map as ImmutableMap, fromJS } from 'immutable';
import escapeTextContentForBrowser from 'escape-html';
diff --git a/app/javascript/themes/glitch/reducers/accounts_counters.js b/app/javascript/flavours/glitch/reducers/accounts_counters.js
similarity index 87%
rename from app/javascript/themes/glitch/reducers/accounts_counters.js
rename to app/javascript/flavours/glitch/reducers/accounts_counters.js
index e3728ecd7d7..a9aebd26fce 100644
--- a/app/javascript/themes/glitch/reducers/accounts_counters.js
+++ b/app/javascript/flavours/glitch/reducers/accounts_counters.js
@@ -8,16 +8,16 @@ import {
FOLLOW_REQUESTS_EXPAND_SUCCESS,
ACCOUNT_FOLLOW_SUCCESS,
ACCOUNT_UNFOLLOW_SUCCESS,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import {
BLOCKS_FETCH_SUCCESS,
BLOCKS_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/blocks';
+} from 'flavours/glitch/actions/blocks';
import {
MUTES_FETCH_SUCCESS,
MUTES_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/mutes';
-import { COMPOSE_SUGGESTIONS_READY } from 'themes/glitch/actions/compose';
+} from 'flavours/glitch/actions/mutes';
+import { COMPOSE_SUGGESTIONS_READY } from 'flavours/glitch/actions/compose';
import {
REBLOG_SUCCESS,
UNREBLOG_SUCCESS,
@@ -25,27 +25,27 @@ import {
UNFAVOURITE_SUCCESS,
REBLOGS_FETCH_SUCCESS,
FAVOURITES_FETCH_SUCCESS,
-} from 'themes/glitch/actions/interactions';
+} from 'flavours/glitch/actions/interactions';
import {
TIMELINE_REFRESH_SUCCESS,
TIMELINE_UPDATE,
TIMELINE_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/timelines';
+} from 'flavours/glitch/actions/timelines';
import {
STATUS_FETCH_SUCCESS,
CONTEXT_FETCH_SUCCESS,
-} from 'themes/glitch/actions/statuses';
-import { SEARCH_FETCH_SUCCESS } from 'themes/glitch/actions/search';
+} from 'flavours/glitch/actions/statuses';
+import { SEARCH_FETCH_SUCCESS } from 'flavours/glitch/actions/search';
import {
NOTIFICATIONS_UPDATE,
NOTIFICATIONS_REFRESH_SUCCESS,
NOTIFICATIONS_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/notifications';
+} from 'flavours/glitch/actions/notifications';
import {
FAVOURITED_STATUSES_FETCH_SUCCESS,
FAVOURITED_STATUSES_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/favourites';
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
+} from 'flavours/glitch/actions/favourites';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
import { Map as ImmutableMap, fromJS } from 'immutable';
const normalizeAccount = (state, account) => state.set(account.id, fromJS({
diff --git a/app/javascript/themes/glitch/reducers/alerts.js b/app/javascript/flavours/glitch/reducers/alerts.js
similarity index 93%
rename from app/javascript/themes/glitch/reducers/alerts.js
rename to app/javascript/flavours/glitch/reducers/alerts.js
index ad66b63f689..50f8d30f71c 100644
--- a/app/javascript/themes/glitch/reducers/alerts.js
+++ b/app/javascript/flavours/glitch/reducers/alerts.js
@@ -2,7 +2,7 @@ import {
ALERT_SHOW,
ALERT_DISMISS,
ALERT_CLEAR,
-} from 'themes/glitch/actions/alerts';
+} from 'flavours/glitch/actions/alerts';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
const initialState = ImmutableList([]);
diff --git a/app/javascript/themes/glitch/reducers/cards.js b/app/javascript/flavours/glitch/reducers/cards.js
similarity index 80%
rename from app/javascript/themes/glitch/reducers/cards.js
rename to app/javascript/flavours/glitch/reducers/cards.js
index 35be30444f2..92ecfd08639 100644
--- a/app/javascript/themes/glitch/reducers/cards.js
+++ b/app/javascript/flavours/glitch/reducers/cards.js
@@ -1,4 +1,4 @@
-import { STATUS_CARD_FETCH_SUCCESS } from 'themes/glitch/actions/cards';
+import { STATUS_CARD_FETCH_SUCCESS } from 'flavours/glitch/actions/cards';
import { Map as ImmutableMap, fromJS } from 'immutable';
diff --git a/app/javascript/themes/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js
similarity index 97%
rename from app/javascript/themes/glitch/reducers/compose.js
rename to app/javascript/flavours/glitch/reducers/compose.js
index be359fcb425..aaa36b69611 100644
--- a/app/javascript/themes/glitch/reducers/compose.js
+++ b/app/javascript/flavours/glitch/reducers/compose.js
@@ -28,12 +28,12 @@ import {
COMPOSE_UPLOAD_CHANGE_FAIL,
COMPOSE_DOODLE_SET,
COMPOSE_RESET,
-} from 'themes/glitch/actions/compose';
-import { TIMELINE_DELETE } from 'themes/glitch/actions/timelines';
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
+} from 'flavours/glitch/actions/compose';
+import { TIMELINE_DELETE } from 'flavours/glitch/actions/timelines';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
-import uuid from 'themes/glitch/util/uuid';
-import { me } from 'themes/glitch/util/initial_state';
+import uuid from 'flavours/glitch/util/uuid';
+import { me } from 'flavours/glitch/util/initial_state';
const initialState = ImmutableMap({
mounted: false,
diff --git a/app/javascript/themes/glitch/reducers/contexts.js b/app/javascript/flavours/glitch/reducers/contexts.js
similarity index 91%
rename from app/javascript/themes/glitch/reducers/contexts.js
rename to app/javascript/flavours/glitch/reducers/contexts.js
index 56c930bd5b5..53e93a5892b 100644
--- a/app/javascript/themes/glitch/reducers/contexts.js
+++ b/app/javascript/flavours/glitch/reducers/contexts.js
@@ -1,5 +1,5 @@
-import { CONTEXT_FETCH_SUCCESS } from 'themes/glitch/actions/statuses';
-import { TIMELINE_DELETE, TIMELINE_CONTEXT_UPDATE } from 'themes/glitch/actions/timelines';
+import { CONTEXT_FETCH_SUCCESS } from 'flavours/glitch/actions/statuses';
+import { TIMELINE_DELETE, TIMELINE_CONTEXT_UPDATE } from 'flavours/glitch/actions/timelines';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
const initialState = ImmutableMap({
diff --git a/app/javascript/themes/glitch/reducers/custom_emojis.js b/app/javascript/flavours/glitch/reducers/custom_emojis.js
similarity index 63%
rename from app/javascript/themes/glitch/reducers/custom_emojis.js
rename to app/javascript/flavours/glitch/reducers/custom_emojis.js
index e3f1e001809..592cea8dcda 100644
--- a/app/javascript/themes/glitch/reducers/custom_emojis.js
+++ b/app/javascript/flavours/glitch/reducers/custom_emojis.js
@@ -1,7 +1,7 @@
import { List as ImmutableList } from 'immutable';
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
-import { search as emojiSearch } from 'themes/glitch/util/emoji/emoji_mart_search_light';
-import { buildCustomEmojis } from 'themes/glitch/util/emoji';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
+import { search as emojiSearch } from 'flavours/glitch/util/emoji/emoji_mart_search_light';
+import { buildCustomEmojis } from 'flavours/glitch/util/emoji';
const initialState = ImmutableList();
diff --git a/app/javascript/themes/glitch/reducers/height_cache.js b/app/javascript/flavours/glitch/reducers/height_cache.js
similarity index 85%
rename from app/javascript/themes/glitch/reducers/height_cache.js
rename to app/javascript/flavours/glitch/reducers/height_cache.js
index 93c31b42c13..8b05e0b1960 100644
--- a/app/javascript/themes/glitch/reducers/height_cache.js
+++ b/app/javascript/flavours/glitch/reducers/height_cache.js
@@ -1,5 +1,5 @@
import { Map as ImmutableMap } from 'immutable';
-import { HEIGHT_CACHE_SET, HEIGHT_CACHE_CLEAR } from 'themes/glitch/actions/height_cache';
+import { HEIGHT_CACHE_SET, HEIGHT_CACHE_CLEAR } from 'flavours/glitch/actions/height_cache';
const initialState = ImmutableMap();
diff --git a/app/javascript/themes/glitch/reducers/index.js b/app/javascript/flavours/glitch/reducers/index.js
similarity index 100%
rename from app/javascript/themes/glitch/reducers/index.js
rename to app/javascript/flavours/glitch/reducers/index.js
diff --git a/app/javascript/themes/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js
similarity index 88%
rename from app/javascript/themes/glitch/reducers/local_settings.js
rename to app/javascript/flavours/glitch/reducers/local_settings.js
index b1ffa047ebd..69d98741b63 100644
--- a/app/javascript/themes/glitch/reducers/local_settings.js
+++ b/app/javascript/flavours/glitch/reducers/local_settings.js
@@ -2,8 +2,8 @@
import { Map as ImmutableMap } from 'immutable';
// Our imports.
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
-import { LOCAL_SETTING_CHANGE } from 'themes/glitch/actions/local_settings';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
+import { LOCAL_SETTING_CHANGE } from 'flavours/glitch/actions/local_settings';
const initialState = ImmutableMap({
layout : 'auto',
diff --git a/app/javascript/themes/glitch/reducers/media_attachments.js b/app/javascript/flavours/glitch/reducers/media_attachments.js
similarity index 83%
rename from app/javascript/themes/glitch/reducers/media_attachments.js
rename to app/javascript/flavours/glitch/reducers/media_attachments.js
index 69a44639cbc..6e605857668 100644
--- a/app/javascript/themes/glitch/reducers/media_attachments.js
+++ b/app/javascript/flavours/glitch/reducers/media_attachments.js
@@ -1,4 +1,4 @@
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
import { Map as ImmutableMap } from 'immutable';
const initialState = ImmutableMap({
diff --git a/app/javascript/themes/glitch/reducers/meta.js b/app/javascript/flavours/glitch/reducers/meta.js
similarity index 84%
rename from app/javascript/themes/glitch/reducers/meta.js
rename to app/javascript/flavours/glitch/reducers/meta.js
index 2249f1d78d6..a98dc436a01 100644
--- a/app/javascript/themes/glitch/reducers/meta.js
+++ b/app/javascript/flavours/glitch/reducers/meta.js
@@ -1,4 +1,4 @@
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
import { Map as ImmutableMap } from 'immutable';
const initialState = ImmutableMap({
diff --git a/app/javascript/themes/glitch/reducers/modal.js b/app/javascript/flavours/glitch/reducers/modal.js
similarity index 81%
rename from app/javascript/themes/glitch/reducers/modal.js
rename to app/javascript/flavours/glitch/reducers/modal.js
index 97fb3120367..80bc11dda40 100644
--- a/app/javascript/themes/glitch/reducers/modal.js
+++ b/app/javascript/flavours/glitch/reducers/modal.js
@@ -1,4 +1,4 @@
-import { MODAL_OPEN, MODAL_CLOSE } from 'themes/glitch/actions/modal';
+import { MODAL_OPEN, MODAL_CLOSE } from 'flavours/glitch/actions/modal';
const initialState = {
modalType: null,
diff --git a/app/javascript/themes/glitch/reducers/mutes.js b/app/javascript/flavours/glitch/reducers/mutes.js
similarity index 94%
rename from app/javascript/themes/glitch/reducers/mutes.js
rename to app/javascript/flavours/glitch/reducers/mutes.js
index 8fe4ae0c36f..8f52a7704ab 100644
--- a/app/javascript/themes/glitch/reducers/mutes.js
+++ b/app/javascript/flavours/glitch/reducers/mutes.js
@@ -3,7 +3,7 @@ import Immutable from 'immutable';
import {
MUTES_INIT_MODAL,
MUTES_TOGGLE_HIDE_NOTIFICATIONS,
-} from 'themes/glitch/actions/mutes';
+} from 'flavours/glitch/actions/mutes';
const initialState = Immutable.Map({
new: Immutable.Map({
diff --git a/app/javascript/themes/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js
similarity index 97%
rename from app/javascript/themes/glitch/reducers/notifications.js
rename to app/javascript/flavours/glitch/reducers/notifications.js
index c4f505053b6..fb2b3f54984 100644
--- a/app/javascript/themes/glitch/reducers/notifications.js
+++ b/app/javascript/flavours/glitch/reducers/notifications.js
@@ -14,12 +14,12 @@ import {
NOTIFICATIONS_DELETE_MARKED_FAIL,
NOTIFICATIONS_ENTER_CLEARING_MODE,
NOTIFICATIONS_MARK_ALL_FOR_DELETE,
-} from 'themes/glitch/actions/notifications';
+} from 'flavours/glitch/actions/notifications';
import {
ACCOUNT_BLOCK_SUCCESS,
ACCOUNT_MUTE_SUCCESS,
-} from 'themes/glitch/actions/accounts';
-import { TIMELINE_DELETE } from 'themes/glitch/actions/timelines';
+} from 'flavours/glitch/actions/accounts';
+import { TIMELINE_DELETE } from 'flavours/glitch/actions/timelines';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
const initialState = ImmutableMap({
diff --git a/app/javascript/themes/glitch/reducers/push_notifications.js b/app/javascript/flavours/glitch/reducers/push_notifications.js
similarity index 91%
rename from app/javascript/themes/glitch/reducers/push_notifications.js
rename to app/javascript/flavours/glitch/reducers/push_notifications.js
index 744e4a0ebdc..f0a800d23cf 100644
--- a/app/javascript/themes/glitch/reducers/push_notifications.js
+++ b/app/javascript/flavours/glitch/reducers/push_notifications.js
@@ -1,5 +1,5 @@
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
-import { SET_BROWSER_SUPPORT, SET_SUBSCRIPTION, CLEAR_SUBSCRIPTION, ALERTS_CHANGE } from 'themes/glitch/actions/push_notifications';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
+import { SET_BROWSER_SUPPORT, SET_SUBSCRIPTION, CLEAR_SUBSCRIPTION, ALERTS_CHANGE } from 'flavours/glitch/actions/push_notifications';
import Immutable from 'immutable';
const initialState = Immutable.Map({
diff --git a/app/javascript/themes/glitch/reducers/relationships.js b/app/javascript/flavours/glitch/reducers/relationships.js
similarity index 93%
rename from app/javascript/themes/glitch/reducers/relationships.js
rename to app/javascript/flavours/glitch/reducers/relationships.js
index d9135d6da88..6303089ac7a 100644
--- a/app/javascript/themes/glitch/reducers/relationships.js
+++ b/app/javascript/flavours/glitch/reducers/relationships.js
@@ -6,11 +6,11 @@ import {
ACCOUNT_MUTE_SUCCESS,
ACCOUNT_UNMUTE_SUCCESS,
RELATIONSHIPS_FETCH_SUCCESS,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import {
DOMAIN_BLOCK_SUCCESS,
DOMAIN_UNBLOCK_SUCCESS,
-} from 'themes/glitch/actions/domain_blocks';
+} from 'flavours/glitch/actions/domain_blocks';
import { Map as ImmutableMap, fromJS } from 'immutable';
const normalizeRelationship = (state, relationship) => state.set(relationship.id, fromJS(relationship));
diff --git a/app/javascript/themes/glitch/reducers/reports.js b/app/javascript/flavours/glitch/reducers/reports.js
similarity index 97%
rename from app/javascript/themes/glitch/reducers/reports.js
rename to app/javascript/flavours/glitch/reducers/reports.js
index b714374eaca..c18fbcdc617 100644
--- a/app/javascript/themes/glitch/reducers/reports.js
+++ b/app/javascript/flavours/glitch/reducers/reports.js
@@ -6,7 +6,7 @@ import {
REPORT_CANCEL,
REPORT_STATUS_TOGGLE,
REPORT_COMMENT_CHANGE,
-} from 'themes/glitch/actions/reports';
+} from 'flavours/glitch/actions/reports';
import { Map as ImmutableMap, Set as ImmutableSet } from 'immutable';
const initialState = ImmutableMap({
diff --git a/app/javascript/themes/glitch/reducers/search.js b/app/javascript/flavours/glitch/reducers/search.js
similarity index 90%
rename from app/javascript/themes/glitch/reducers/search.js
rename to app/javascript/flavours/glitch/reducers/search.js
index aec9e2efb20..f9bf9209802 100644
--- a/app/javascript/themes/glitch/reducers/search.js
+++ b/app/javascript/flavours/glitch/reducers/search.js
@@ -3,8 +3,8 @@ import {
SEARCH_CLEAR,
SEARCH_FETCH_SUCCESS,
SEARCH_SHOW,
-} from 'themes/glitch/actions/search';
-import { COMPOSE_MENTION, COMPOSE_REPLY } from 'themes/glitch/actions/compose';
+} from 'flavours/glitch/actions/search';
+import { COMPOSE_MENTION, COMPOSE_REPLY } from 'flavours/glitch/actions/compose';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
const initialState = ImmutableMap({
diff --git a/app/javascript/themes/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js
similarity index 88%
rename from app/javascript/themes/glitch/reducers/settings.js
rename to app/javascript/flavours/glitch/reducers/settings.js
index c22bbbd8dc8..ceafbc46792 100644
--- a/app/javascript/themes/glitch/reducers/settings.js
+++ b/app/javascript/flavours/glitch/reducers/settings.js
@@ -1,9 +1,9 @@
-import { SETTING_CHANGE, SETTING_SAVE } from 'themes/glitch/actions/settings';
-import { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE } from 'themes/glitch/actions/columns';
-import { STORE_HYDRATE } from 'themes/glitch/actions/store';
-import { EMOJI_USE } from 'themes/glitch/actions/emojis';
+import { SETTING_CHANGE, SETTING_SAVE } from 'flavours/glitch/actions/settings';
+import { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE } from 'flavours/glitch/actions/columns';
+import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
+import { EMOJI_USE } from 'flavours/glitch/actions/emojis';
import { Map as ImmutableMap, fromJS } from 'immutable';
-import uuid from 'themes/glitch/util/uuid';
+import uuid from 'flavours/glitch/util/uuid';
const initialState = ImmutableMap({
saved: true,
diff --git a/app/javascript/themes/glitch/reducers/status_lists.js b/app/javascript/flavours/glitch/reducers/status_lists.js
similarity index 94%
rename from app/javascript/themes/glitch/reducers/status_lists.js
rename to app/javascript/flavours/glitch/reducers/status_lists.js
index 8dc7d374e3b..5a3d0db0cab 100644
--- a/app/javascript/themes/glitch/reducers/status_lists.js
+++ b/app/javascript/flavours/glitch/reducers/status_lists.js
@@ -1,17 +1,17 @@
import {
FAVOURITED_STATUSES_FETCH_SUCCESS,
FAVOURITED_STATUSES_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/favourites';
+} from 'flavours/glitch/actions/favourites';
import {
PINNED_STATUSES_FETCH_SUCCESS,
-} from 'themes/glitch/actions/pin_statuses';
+} from 'flavours/glitch/actions/pin_statuses';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import {
FAVOURITE_SUCCESS,
UNFAVOURITE_SUCCESS,
PIN_SUCCESS,
UNPIN_SUCCESS,
-} from 'themes/glitch/actions/interactions';
+} from 'flavours/glitch/actions/interactions';
const initialState = ImmutableMap({
favourites: ImmutableMap({
diff --git a/app/javascript/themes/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js
similarity index 90%
rename from app/javascript/themes/glitch/reducers/statuses.js
rename to app/javascript/flavours/glitch/reducers/statuses.js
index ef808686558..410bc013b95 100644
--- a/app/javascript/themes/glitch/reducers/statuses.js
+++ b/app/javascript/flavours/glitch/reducers/statuses.js
@@ -9,37 +9,37 @@ import {
UNFAVOURITE_SUCCESS,
PIN_SUCCESS,
UNPIN_SUCCESS,
-} from 'themes/glitch/actions/interactions';
+} from 'flavours/glitch/actions/interactions';
import {
STATUS_FETCH_SUCCESS,
CONTEXT_FETCH_SUCCESS,
STATUS_MUTE_SUCCESS,
STATUS_UNMUTE_SUCCESS,
-} from 'themes/glitch/actions/statuses';
+} from 'flavours/glitch/actions/statuses';
import {
TIMELINE_REFRESH_SUCCESS,
TIMELINE_UPDATE,
TIMELINE_DELETE,
TIMELINE_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/timelines';
+} from 'flavours/glitch/actions/timelines';
import {
ACCOUNT_BLOCK_SUCCESS,
ACCOUNT_MUTE_SUCCESS,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import {
NOTIFICATIONS_UPDATE,
NOTIFICATIONS_REFRESH_SUCCESS,
NOTIFICATIONS_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/notifications';
+} from 'flavours/glitch/actions/notifications';
import {
FAVOURITED_STATUSES_FETCH_SUCCESS,
FAVOURITED_STATUSES_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/favourites';
+} from 'flavours/glitch/actions/favourites';
import {
PINNED_STATUSES_FETCH_SUCCESS,
-} from 'themes/glitch/actions/pin_statuses';
-import { SEARCH_FETCH_SUCCESS } from 'themes/glitch/actions/search';
-import emojify from 'themes/glitch/util/emoji';
+} from 'flavours/glitch/actions/pin_statuses';
+import { SEARCH_FETCH_SUCCESS } from 'flavours/glitch/actions/search';
+import emojify from 'flavours/glitch/util/emoji';
import { Map as ImmutableMap, fromJS } from 'immutable';
import escapeTextContentForBrowser from 'escape-html';
diff --git a/app/javascript/themes/glitch/reducers/timelines.js b/app/javascript/flavours/glitch/reducers/timelines.js
similarity index 98%
rename from app/javascript/themes/glitch/reducers/timelines.js
rename to app/javascript/flavours/glitch/reducers/timelines.js
index 7f19a18971f..679e1601eb2 100644
--- a/app/javascript/themes/glitch/reducers/timelines.js
+++ b/app/javascript/flavours/glitch/reducers/timelines.js
@@ -10,12 +10,12 @@ import {
TIMELINE_SCROLL_TOP,
TIMELINE_CONNECT,
TIMELINE_DISCONNECT,
-} from 'themes/glitch/actions/timelines';
+} from 'flavours/glitch/actions/timelines';
import {
ACCOUNT_BLOCK_SUCCESS,
ACCOUNT_MUTE_SUCCESS,
ACCOUNT_UNFOLLOW_SUCCESS,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
const initialState = ImmutableMap();
diff --git a/app/javascript/themes/glitch/reducers/user_lists.js b/app/javascript/flavours/glitch/reducers/user_lists.js
similarity index 95%
rename from app/javascript/themes/glitch/reducers/user_lists.js
rename to app/javascript/flavours/glitch/reducers/user_lists.js
index 8c3a7d7480e..a4df9ec8de5 100644
--- a/app/javascript/themes/glitch/reducers/user_lists.js
+++ b/app/javascript/flavours/glitch/reducers/user_lists.js
@@ -7,19 +7,19 @@ import {
FOLLOW_REQUESTS_EXPAND_SUCCESS,
FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
FOLLOW_REQUEST_REJECT_SUCCESS,
-} from 'themes/glitch/actions/accounts';
+} from 'flavours/glitch/actions/accounts';
import {
REBLOGS_FETCH_SUCCESS,
FAVOURITES_FETCH_SUCCESS,
-} from 'themes/glitch/actions/interactions';
+} from 'flavours/glitch/actions/interactions';
import {
BLOCKS_FETCH_SUCCESS,
BLOCKS_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/blocks';
+} from 'flavours/glitch/actions/blocks';
import {
MUTES_FETCH_SUCCESS,
MUTES_EXPAND_SUCCESS,
-} from 'themes/glitch/actions/mutes';
+} from 'flavours/glitch/actions/mutes';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
const initialState = ImmutableMap({
diff --git a/app/javascript/themes/glitch/selectors/index.js b/app/javascript/flavours/glitch/selectors/index.js
similarity index 100%
rename from app/javascript/themes/glitch/selectors/index.js
rename to app/javascript/flavours/glitch/selectors/index.js
diff --git a/app/javascript/themes/glitch/service_worker/entry.js b/app/javascript/flavours/glitch/service_worker/entry.js
similarity index 100%
rename from app/javascript/themes/glitch/service_worker/entry.js
rename to app/javascript/flavours/glitch/service_worker/entry.js
diff --git a/app/javascript/themes/glitch/service_worker/web_push_notifications.js b/app/javascript/flavours/glitch/service_worker/web_push_notifications.js
similarity index 100%
rename from app/javascript/themes/glitch/service_worker/web_push_notifications.js
rename to app/javascript/flavours/glitch/service_worker/web_push_notifications.js
diff --git a/app/javascript/themes/glitch/store/configureStore.js b/app/javascript/flavours/glitch/store/configureStore.js
similarity index 100%
rename from app/javascript/themes/glitch/store/configureStore.js
rename to app/javascript/flavours/glitch/store/configureStore.js
diff --git a/app/javascript/themes/glitch/styles/_mixins.scss b/app/javascript/flavours/glitch/styles/_mixins.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/_mixins.scss
rename to app/javascript/flavours/glitch/styles/_mixins.scss
diff --git a/app/javascript/themes/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/about.scss
rename to app/javascript/flavours/glitch/styles/about.scss
diff --git a/app/javascript/themes/glitch/styles/accounts.scss b/app/javascript/flavours/glitch/styles/accounts.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/accounts.scss
rename to app/javascript/flavours/glitch/styles/accounts.scss
diff --git a/app/javascript/themes/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/admin.scss
rename to app/javascript/flavours/glitch/styles/admin.scss
diff --git a/app/javascript/themes/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/basics.scss
rename to app/javascript/flavours/glitch/styles/basics.scss
diff --git a/app/javascript/themes/glitch/styles/boost.scss b/app/javascript/flavours/glitch/styles/boost.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/boost.scss
rename to app/javascript/flavours/glitch/styles/boost.scss
diff --git a/app/javascript/themes/glitch/styles/compact_header.scss b/app/javascript/flavours/glitch/styles/compact_header.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/compact_header.scss
rename to app/javascript/flavours/glitch/styles/compact_header.scss
diff --git a/app/javascript/themes/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/components.scss
rename to app/javascript/flavours/glitch/styles/components.scss
diff --git a/app/javascript/themes/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/containers.scss
rename to app/javascript/flavours/glitch/styles/containers.scss
diff --git a/app/javascript/themes/glitch/styles/doodle.scss b/app/javascript/flavours/glitch/styles/doodle.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/doodle.scss
rename to app/javascript/flavours/glitch/styles/doodle.scss
diff --git a/app/javascript/themes/glitch/styles/emoji_picker.scss b/app/javascript/flavours/glitch/styles/emoji_picker.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/emoji_picker.scss
rename to app/javascript/flavours/glitch/styles/emoji_picker.scss
diff --git a/app/javascript/themes/glitch/styles/footer.scss b/app/javascript/flavours/glitch/styles/footer.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/footer.scss
rename to app/javascript/flavours/glitch/styles/footer.scss
diff --git a/app/javascript/themes/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/forms.scss
rename to app/javascript/flavours/glitch/styles/forms.scss
diff --git a/app/javascript/themes/glitch/styles/index.scss b/app/javascript/flavours/glitch/styles/index.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/index.scss
rename to app/javascript/flavours/glitch/styles/index.scss
diff --git a/app/javascript/themes/glitch/styles/landing_strip.scss b/app/javascript/flavours/glitch/styles/landing_strip.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/landing_strip.scss
rename to app/javascript/flavours/glitch/styles/landing_strip.scss
diff --git a/app/javascript/themes/glitch/styles/lists.scss b/app/javascript/flavours/glitch/styles/lists.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/lists.scss
rename to app/javascript/flavours/glitch/styles/lists.scss
diff --git a/app/javascript/themes/glitch/styles/reset copy.scss b/app/javascript/flavours/glitch/styles/reset copy.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/reset copy.scss
rename to app/javascript/flavours/glitch/styles/reset copy.scss
diff --git a/app/javascript/themes/glitch/styles/reset.scss b/app/javascript/flavours/glitch/styles/reset.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/reset.scss
rename to app/javascript/flavours/glitch/styles/reset.scss
diff --git a/app/javascript/themes/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/rtl.scss
rename to app/javascript/flavours/glitch/styles/rtl.scss
diff --git a/app/javascript/themes/glitch/styles/stream_entries.scss b/app/javascript/flavours/glitch/styles/stream_entries.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/stream_entries.scss
rename to app/javascript/flavours/glitch/styles/stream_entries.scss
diff --git a/app/javascript/themes/glitch/styles/tables.scss b/app/javascript/flavours/glitch/styles/tables.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/tables.scss
rename to app/javascript/flavours/glitch/styles/tables.scss
diff --git a/app/javascript/themes/glitch/styles/variables.scss b/app/javascript/flavours/glitch/styles/variables.scss
similarity index 100%
rename from app/javascript/themes/glitch/styles/variables.scss
rename to app/javascript/flavours/glitch/styles/variables.scss
diff --git a/app/javascript/flavours/glitch/theme.yml b/app/javascript/flavours/glitch/theme.yml
new file mode 100644
index 00000000000..9d24f0107ef
--- /dev/null
+++ b/app/javascript/flavours/glitch/theme.yml
@@ -0,0 +1,34 @@
+# (REQUIRED) The location of the pack files.
+pack:
+ about: packs/about.js
+ admin:
+ auth:
+ common:
+ filename: packs/common.js
+ stylesheet: true
+ embed: packs/public.js
+ error:
+ home:
+ filename: packs/home.js
+ preload:
+ - flavours/glitch/async/getting_started
+ - flavours/glitch/async/compose
+ - flavours/glitch/async/home_timeline
+ - flavours/glitch/async/notifications
+ stylesheet: true
+ modal:
+ public: packs/public.js
+ settings:
+ share: packs/share.js
+
+# (OPTIONAL) The directory which contains the pack files.
+# Defaults to the theme directory (`app/javascript/themes/[theme]`),
+# which should be sufficient for like 99% of use-cases lol.
+
+# pack_directory: app/javascript/packs
+
+# (OPTIONAL) By default the theme will fallback to the default theme
+# if a particular pack is not provided. You can specify different
+# fallbacks here, or disable fallback behaviours altogether by
+# specifying a `null` value.
+fallback:
diff --git a/app/javascript/themes/glitch/util/api.js b/app/javascript/flavours/glitch/util/api.js
similarity index 100%
rename from app/javascript/themes/glitch/util/api.js
rename to app/javascript/flavours/glitch/util/api.js
diff --git a/app/javascript/flavours/glitch/util/async-components.js b/app/javascript/flavours/glitch/util/async-components.js
new file mode 100644
index 00000000000..b7ac4d3ec50
--- /dev/null
+++ b/app/javascript/flavours/glitch/util/async-components.js
@@ -0,0 +1,115 @@
+export function EmojiPicker () {
+ return import(/* webpackChunkName: "flavours/glitch/async/emoji_picker" */'flavours/glitch/util/emoji/emoji_picker');
+}
+
+export function Compose () {
+ return import(/* webpackChunkName: "flavours/glitch/async/compose" */'flavours/glitch/features/compose');
+}
+
+export function Notifications () {
+ return import(/* webpackChunkName: "flavours/glitch/async/notifications" */'flavours/glitch/features/notifications');
+}
+
+export function HomeTimeline () {
+ return import(/* webpackChunkName: "flavours/glitch/async/home_timeline" */'flavours/glitch/features/home_timeline');
+}
+
+export function PublicTimeline () {
+ return import(/* webpackChunkName: "flavours/glitch/async/public_timeline" */'flavours/glitch/features/public_timeline');
+}
+
+export function CommunityTimeline () {
+ return import(/* webpackChunkName: "flavours/glitch/async/community_timeline" */'flavours/glitch/features/community_timeline');
+}
+
+export function HashtagTimeline () {
+ return import(/* webpackChunkName: "flavours/glitch/async/hashtag_timeline" */'flavours/glitch/features/hashtag_timeline');
+}
+
+export function DirectTimeline() {
+ return import(/* webpackChunkName: "flavours/glitch/async/direct_timeline" */'flavours/glitch/features/direct_timeline');
+}
+
+export function Status () {
+ return import(/* webpackChunkName: "flavours/glitch/async/status" */'flavours/glitch/features/status');
+}
+
+export function GettingStarted () {
+ return import(/* webpackChunkName: "flavours/glitch/async/getting_started" */'flavours/glitch/features/getting_started');
+}
+
+export function PinnedStatuses () {
+ return import(/* webpackChunkName: "flavours/glitch/async/pinned_statuses" */'flavours/glitch/features/pinned_statuses');
+}
+
+export function AccountTimeline () {
+ return import(/* webpackChunkName: "flavours/glitch/async/account_timeline" */'flavours/glitch/features/account_timeline');
+}
+
+export function AccountGallery () {
+ return import(/* webpackChunkName: "flavours/glitch/async/account_gallery" */'flavours/glitch/features/account_gallery');
+}
+
+export function Followers () {
+ return import(/* webpackChunkName: "flavours/glitch/async/followers" */'flavours/glitch/features/followers');
+}
+
+export function Following () {
+ return import(/* webpackChunkName: "flavours/glitch/async/following" */'flavours/glitch/features/following');
+}
+
+export function Reblogs () {
+ return import(/* webpackChunkName: "flavours/glitch/async/reblogs" */'flavours/glitch/features/reblogs');
+}
+
+export function Favourites () {
+ return import(/* webpackChunkName: "flavours/glitch/async/favourites" */'flavours/glitch/features/favourites');
+}
+
+export function FollowRequests () {
+ return import(/* webpackChunkName: "flavours/glitch/async/follow_requests" */'flavours/glitch/features/follow_requests');
+}
+
+export function GenericNotFound () {
+ return import(/* webpackChunkName: "flavours/glitch/async/generic_not_found" */'flavours/glitch/features/generic_not_found');
+}
+
+export function FavouritedStatuses () {
+ return import(/* webpackChunkName: "flavours/glitch/async/favourited_statuses" */'flavours/glitch/features/favourited_statuses');
+}
+
+export function Blocks () {
+ return import(/* webpackChunkName: "flavours/glitch/async/blocks" */'flavours/glitch/features/blocks');
+}
+
+export function Mutes () {
+ return import(/* webpackChunkName: "flavours/glitch/async/mutes" */'flavours/glitch/features/mutes');
+}
+
+export function OnboardingModal () {
+ return import(/* webpackChunkName: "flavours/glitch/async/onboarding_modal" */'flavours/glitch/features/ui/components/onboarding_modal');
+}
+
+export function MuteModal () {
+ return import(/* webpackChunkName: "flavours/glitch/async/mute_modal" */'flavours/glitch/features/ui/components/mute_modal');
+}
+
+export function ReportModal () {
+ return import(/* webpackChunkName: "flavours/glitch/async/report_modal" */'flavours/glitch/features/ui/components/report_modal');
+}
+
+export function SettingsModal () {
+ return import(/* webpackChunkName: "flavours/glitch/async/settings_modal" */'flavours/glitch/features/local_settings');
+}
+
+export function MediaGallery () {
+ return import(/* webpackChunkName: "flavours/glitch/async/media_gallery" */'flavours/glitch/components/media_gallery');
+}
+
+export function Video () {
+ return import(/* webpackChunkName: "flavours/glitch/async/video" */'flavours/glitch/features/video');
+}
+
+export function EmbedModal () {
+ return import(/* webpackChunkName: "flavours/glitch/async/embed_modal" */'flavours/glitch/features/ui/components/embed_modal');
+}
diff --git a/app/javascript/themes/glitch/util/base_polyfills.js b/app/javascript/flavours/glitch/util/base_polyfills.js
similarity index 100%
rename from app/javascript/themes/glitch/util/base_polyfills.js
rename to app/javascript/flavours/glitch/util/base_polyfills.js
diff --git a/app/javascript/themes/glitch/util/bio_metadata.js b/app/javascript/flavours/glitch/util/bio_metadata.js
similarity index 100%
rename from app/javascript/themes/glitch/util/bio_metadata.js
rename to app/javascript/flavours/glitch/util/bio_metadata.js
diff --git a/app/javascript/themes/glitch/util/counter.js b/app/javascript/flavours/glitch/util/counter.js
similarity index 100%
rename from app/javascript/themes/glitch/util/counter.js
rename to app/javascript/flavours/glitch/util/counter.js
diff --git a/app/javascript/themes/glitch/util/emoji/emoji_compressed.js b/app/javascript/flavours/glitch/util/emoji/emoji_compressed.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/emoji_compressed.js
rename to app/javascript/flavours/glitch/util/emoji/emoji_compressed.js
diff --git a/app/javascript/themes/glitch/util/emoji/emoji_map.json b/app/javascript/flavours/glitch/util/emoji/emoji_map.json
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/emoji_map.json
rename to app/javascript/flavours/glitch/util/emoji/emoji_map.json
diff --git a/app/javascript/themes/glitch/util/emoji/emoji_mart_data_light.js b/app/javascript/flavours/glitch/util/emoji/emoji_mart_data_light.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/emoji_mart_data_light.js
rename to app/javascript/flavours/glitch/util/emoji/emoji_mart_data_light.js
diff --git a/app/javascript/themes/glitch/util/emoji/emoji_mart_search_light.js b/app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/emoji_mart_search_light.js
rename to app/javascript/flavours/glitch/util/emoji/emoji_mart_search_light.js
diff --git a/app/javascript/themes/glitch/util/emoji/emoji_picker.js b/app/javascript/flavours/glitch/util/emoji/emoji_picker.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/emoji_picker.js
rename to app/javascript/flavours/glitch/util/emoji/emoji_picker.js
diff --git a/app/javascript/themes/glitch/util/emoji/emoji_unicode_mapping_light.js b/app/javascript/flavours/glitch/util/emoji/emoji_unicode_mapping_light.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/emoji_unicode_mapping_light.js
rename to app/javascript/flavours/glitch/util/emoji/emoji_unicode_mapping_light.js
diff --git a/app/javascript/themes/glitch/util/emoji/emoji_utils.js b/app/javascript/flavours/glitch/util/emoji/emoji_utils.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/emoji_utils.js
rename to app/javascript/flavours/glitch/util/emoji/emoji_utils.js
diff --git a/app/javascript/themes/glitch/util/emoji/index.js b/app/javascript/flavours/glitch/util/emoji/index.js
similarity index 97%
rename from app/javascript/themes/glitch/util/emoji/index.js
rename to app/javascript/flavours/glitch/util/emoji/index.js
index 8c45a58fec4..31c3e14cace 100644
--- a/app/javascript/themes/glitch/util/emoji/index.js
+++ b/app/javascript/flavours/glitch/util/emoji/index.js
@@ -1,4 +1,4 @@
-import { autoPlayGif } from 'themes/glitch/util/initial_state';
+import { autoPlayGif } from 'flavours/glitch/util/initial_state';
import unicodeMapping from './emoji_unicode_mapping_light';
import Trie from 'substring-trie';
diff --git a/app/javascript/themes/glitch/util/emoji/unicode_to_filename.js b/app/javascript/flavours/glitch/util/emoji/unicode_to_filename.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/unicode_to_filename.js
rename to app/javascript/flavours/glitch/util/emoji/unicode_to_filename.js
diff --git a/app/javascript/themes/glitch/util/emoji/unicode_to_unified_name.js b/app/javascript/flavours/glitch/util/emoji/unicode_to_unified_name.js
similarity index 100%
rename from app/javascript/themes/glitch/util/emoji/unicode_to_unified_name.js
rename to app/javascript/flavours/glitch/util/emoji/unicode_to_unified_name.js
diff --git a/app/javascript/themes/glitch/util/extra_polyfills.js b/app/javascript/flavours/glitch/util/extra_polyfills.js
similarity index 100%
rename from app/javascript/themes/glitch/util/extra_polyfills.js
rename to app/javascript/flavours/glitch/util/extra_polyfills.js
diff --git a/app/javascript/themes/glitch/util/fullscreen.js b/app/javascript/flavours/glitch/util/fullscreen.js
similarity index 100%
rename from app/javascript/themes/glitch/util/fullscreen.js
rename to app/javascript/flavours/glitch/util/fullscreen.js
diff --git a/app/javascript/themes/glitch/util/get_rect_from_entry.js b/app/javascript/flavours/glitch/util/get_rect_from_entry.js
similarity index 100%
rename from app/javascript/themes/glitch/util/get_rect_from_entry.js
rename to app/javascript/flavours/glitch/util/get_rect_from_entry.js
diff --git a/app/javascript/themes/glitch/util/initial_state.js b/app/javascript/flavours/glitch/util/initial_state.js
similarity index 100%
rename from app/javascript/themes/glitch/util/initial_state.js
rename to app/javascript/flavours/glitch/util/initial_state.js
diff --git a/app/javascript/themes/glitch/util/intersection_observer_wrapper.js b/app/javascript/flavours/glitch/util/intersection_observer_wrapper.js
similarity index 100%
rename from app/javascript/themes/glitch/util/intersection_observer_wrapper.js
rename to app/javascript/flavours/glitch/util/intersection_observer_wrapper.js
diff --git a/app/javascript/themes/glitch/util/is_mobile.js b/app/javascript/flavours/glitch/util/is_mobile.js
similarity index 100%
rename from app/javascript/themes/glitch/util/is_mobile.js
rename to app/javascript/flavours/glitch/util/is_mobile.js
diff --git a/app/javascript/themes/glitch/util/link_header.js b/app/javascript/flavours/glitch/util/link_header.js
similarity index 100%
rename from app/javascript/themes/glitch/util/link_header.js
rename to app/javascript/flavours/glitch/util/link_header.js
diff --git a/app/javascript/themes/glitch/util/load_polyfills.js b/app/javascript/flavours/glitch/util/load_polyfills.js
similarity index 100%
rename from app/javascript/themes/glitch/util/load_polyfills.js
rename to app/javascript/flavours/glitch/util/load_polyfills.js
diff --git a/app/javascript/themes/glitch/util/main.js b/app/javascript/flavours/glitch/util/main.js
similarity index 95%
rename from app/javascript/themes/glitch/util/main.js
rename to app/javascript/flavours/glitch/util/main.js
index c10a64ded0f..fe57fa962a5 100644
--- a/app/javascript/themes/glitch/util/main.js
+++ b/app/javascript/flavours/glitch/util/main.js
@@ -1,5 +1,5 @@
import * as WebPushSubscription from './web_push_subscription';
-import Mastodon from 'themes/glitch/containers/mastodon';
+import Mastodon from 'flavours/glitch/containers/mastodon';
import React from 'react';
import ReactDOM from 'react-dom';
import ready from './ready';
diff --git a/app/javascript/themes/glitch/util/optional_motion.js b/app/javascript/flavours/glitch/util/optional_motion.js
similarity index 68%
rename from app/javascript/themes/glitch/util/optional_motion.js
rename to app/javascript/flavours/glitch/util/optional_motion.js
index b8a57b22f96..eecb6634e97 100644
--- a/app/javascript/themes/glitch/util/optional_motion.js
+++ b/app/javascript/flavours/glitch/util/optional_motion.js
@@ -1,4 +1,4 @@
-import { reduceMotion } from 'themes/glitch/util/initial_state';
+import { reduceMotion } from 'flavours/glitch/util/initial_state';
import ReducedMotion from './reduced_motion';
import Motion from 'react-motion/lib/Motion';
diff --git a/app/javascript/themes/glitch/util/performance.js b/app/javascript/flavours/glitch/util/performance.js
similarity index 100%
rename from app/javascript/themes/glitch/util/performance.js
rename to app/javascript/flavours/glitch/util/performance.js
diff --git a/app/javascript/themes/glitch/util/react_router_helpers.js b/app/javascript/flavours/glitch/util/react_router_helpers.js
similarity index 85%
rename from app/javascript/themes/glitch/util/react_router_helpers.js
rename to app/javascript/flavours/glitch/util/react_router_helpers.js
index c02fb524795..1dba5e9bb0b 100644
--- a/app/javascript/themes/glitch/util/react_router_helpers.js
+++ b/app/javascript/flavours/glitch/util/react_router_helpers.js
@@ -2,9 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Switch, Route } from 'react-router-dom';
-import ColumnLoading from 'themes/glitch/features/ui/components/column_loading';
-import BundleColumnError from 'themes/glitch/features/ui/components/bundle_column_error';
-import BundleContainer from 'themes/glitch/features/ui/containers/bundle_container';
+import ColumnLoading from 'flavours/glitch/features/ui/components/column_loading';
+import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
+import BundleContainer from 'flavours/glitch/features/ui/containers/bundle_container';
// Small wrapper to pass multiColumn to the route components
export class WrappedSwitch extends React.PureComponent {
diff --git a/app/javascript/themes/glitch/util/ready.js b/app/javascript/flavours/glitch/util/ready.js
similarity index 100%
rename from app/javascript/themes/glitch/util/ready.js
rename to app/javascript/flavours/glitch/util/ready.js
diff --git a/app/javascript/themes/glitch/util/reduced_motion.js b/app/javascript/flavours/glitch/util/reduced_motion.js
similarity index 100%
rename from app/javascript/themes/glitch/util/reduced_motion.js
rename to app/javascript/flavours/glitch/util/reduced_motion.js
diff --git a/app/javascript/themes/glitch/util/rtl.js b/app/javascript/flavours/glitch/util/rtl.js
similarity index 100%
rename from app/javascript/themes/glitch/util/rtl.js
rename to app/javascript/flavours/glitch/util/rtl.js
diff --git a/app/javascript/themes/glitch/util/schedule_idle_task.js b/app/javascript/flavours/glitch/util/schedule_idle_task.js
similarity index 100%
rename from app/javascript/themes/glitch/util/schedule_idle_task.js
rename to app/javascript/flavours/glitch/util/schedule_idle_task.js
diff --git a/app/javascript/themes/glitch/util/scroll.js b/app/javascript/flavours/glitch/util/scroll.js
similarity index 100%
rename from app/javascript/themes/glitch/util/scroll.js
rename to app/javascript/flavours/glitch/util/scroll.js
diff --git a/app/javascript/themes/glitch/util/stream.js b/app/javascript/flavours/glitch/util/stream.js
similarity index 100%
rename from app/javascript/themes/glitch/util/stream.js
rename to app/javascript/flavours/glitch/util/stream.js
diff --git a/app/javascript/themes/glitch/util/url_regex.js b/app/javascript/flavours/glitch/util/url_regex.js
similarity index 100%
rename from app/javascript/themes/glitch/util/url_regex.js
rename to app/javascript/flavours/glitch/util/url_regex.js
diff --git a/app/javascript/themes/glitch/util/uuid.js b/app/javascript/flavours/glitch/util/uuid.js
similarity index 100%
rename from app/javascript/themes/glitch/util/uuid.js
rename to app/javascript/flavours/glitch/util/uuid.js
diff --git a/app/javascript/themes/glitch/util/web_push_subscription.js b/app/javascript/flavours/glitch/util/web_push_subscription.js
similarity index 97%
rename from app/javascript/themes/glitch/util/web_push_subscription.js
rename to app/javascript/flavours/glitch/util/web_push_subscription.js
index 70b26105b8f..de185b6d92f 100644
--- a/app/javascript/themes/glitch/util/web_push_subscription.js
+++ b/app/javascript/flavours/glitch/util/web_push_subscription.js
@@ -1,6 +1,6 @@
import axios from 'axios';
-import { store } from 'themes/glitch/containers/mastodon';
-import { setBrowserSupport, setSubscription, clearSubscription } from 'themes/glitch/actions/push_notifications';
+import { store } from 'flavours/glitch/containers/mastodon';
+import { setBrowserSupport, setSubscription, clearSubscription } from 'flavours/glitch/actions/push_notifications';
// Taken from https://www.npmjs.com/package/web-push
const urlBase64ToUint8Array = (base64String) => {
diff --git a/app/javascript/flavours/vanilla/theme.yml b/app/javascript/flavours/vanilla/theme.yml
new file mode 100644
index 00000000000..67fd9723e81
--- /dev/null
+++ b/app/javascript/flavours/vanilla/theme.yml
@@ -0,0 +1,33 @@
+# (REQUIRED) The location of the pack files inside `pack_directory`.
+pack:
+ about: about.js
+ admin:
+ auth:
+ common:
+ filename: common.js
+ stylesheet: true
+ embed: public.js
+ error:
+ home:
+ filename: application.js
+ preload:
+ - features/getting_started
+ - features/compose
+ - features/home_timeline
+ - features/notifications
+ modal:
+ public: public.js
+ settings:
+ share: share.js
+
+# (OPTIONAL) The directory which contains the pack files.
+# Defaults to the theme directory (`app/javascript/themes/[theme]`),
+# but in the case of the vanilla Mastodon theme the pack files are
+# somewhere else.
+pack_directory: app/javascript/packs
+
+# (OPTIONAL) By default the theme will fallback to the default theme
+# if a particular pack is not provided. You can specify different
+# fallbacks here, or disable fallback behaviours altogether by
+# specifying a `null` value.
+fallback:
diff --git a/app/javascript/fonts/premillenium/MSSansSerif.ttf b/app/javascript/fonts/premillenium/MSSansSerif.ttf
new file mode 100644
index 00000000000..3afd76ff2db
Binary files /dev/null and b/app/javascript/fonts/premillenium/MSSansSerif.ttf differ
diff --git a/app/javascript/images/icon_about.png b/app/javascript/images/icon_about.png
new file mode 100644
index 00000000000..08b76dcd9dd
Binary files /dev/null and b/app/javascript/images/icon_about.png differ
diff --git a/app/javascript/images/icon_blocks.png b/app/javascript/images/icon_blocks.png
new file mode 100644
index 00000000000..8b1490875fc
Binary files /dev/null and b/app/javascript/images/icon_blocks.png differ
diff --git a/app/javascript/images/icon_home.png b/app/javascript/images/icon_home.png
new file mode 100644
index 00000000000..66ce779c0d7
Binary files /dev/null and b/app/javascript/images/icon_home.png differ
diff --git a/app/javascript/images/icon_likes.png b/app/javascript/images/icon_likes.png
new file mode 100644
index 00000000000..17d7a9c59bd
Binary files /dev/null and b/app/javascript/images/icon_likes.png differ
diff --git a/app/javascript/images/icon_local.png b/app/javascript/images/icon_local.png
new file mode 100644
index 00000000000..5f82df39565
Binary files /dev/null and b/app/javascript/images/icon_local.png differ
diff --git a/app/javascript/images/icon_logout.png b/app/javascript/images/icon_logout.png
new file mode 100644
index 00000000000..7ff806f5862
Binary files /dev/null and b/app/javascript/images/icon_logout.png differ
diff --git a/app/javascript/images/icon_mutes.png b/app/javascript/images/icon_mutes.png
new file mode 100644
index 00000000000..c2225e966eb
Binary files /dev/null and b/app/javascript/images/icon_mutes.png differ
diff --git a/app/javascript/images/icon_pin.png b/app/javascript/images/icon_pin.png
new file mode 100644
index 00000000000..2329d8c54d8
Binary files /dev/null and b/app/javascript/images/icon_pin.png differ
diff --git a/app/javascript/images/icon_public.png b/app/javascript/images/icon_public.png
new file mode 100644
index 00000000000..3c09460dba5
Binary files /dev/null and b/app/javascript/images/icon_public.png differ
diff --git a/app/javascript/images/icon_settings.png b/app/javascript/images/icon_settings.png
new file mode 100644
index 00000000000..07f5c45192a
Binary files /dev/null and b/app/javascript/images/icon_settings.png differ
diff --git a/app/javascript/images/start.png b/app/javascript/images/start.png
new file mode 100644
index 00000000000..7843455b60d
Binary files /dev/null and b/app/javascript/images/start.png differ
diff --git a/app/javascript/locales/index.js b/app/javascript/locales/index.js
new file mode 100644
index 00000000000..421cb7fab01
--- /dev/null
+++ b/app/javascript/locales/index.js
@@ -0,0 +1,9 @@
+let theLocale;
+
+export function setLocale(locale) {
+ theLocale = locale;
+}
+
+export function getLocale() {
+ return theLocale;
+}
diff --git a/app/javascript/mastodon/locales/index.js b/app/javascript/mastodon/locales/index.js
index 421cb7fab01..7e72975618d 100644
--- a/app/javascript/mastodon/locales/index.js
+++ b/app/javascript/mastodon/locales/index.js
@@ -1,9 +1 @@
-let theLocale;
-
-export function setLocale(locale) {
- theLocale = locale;
-}
-
-export function getLocale() {
- return theLocale;
-}
+export * from 'locales';
diff --git a/app/javascript/packs/about.js b/app/javascript/packs/about.js
index 6ce8757dc95..63e12da42cc 100644
--- a/app/javascript/packs/about.js
+++ b/app/javascript/packs/about.js
@@ -1,9 +1,7 @@
-import loadPolyfills from 'themes/glitch/util/load_polyfills';
-
-require.context('../images/', true);
+import loadPolyfills from '../mastodon/load_polyfills';
function loaded() {
- const TimelineContainer = require('themes/glitch/containers/timeline_container').default;
+ const TimelineContainer = require('../mastodon/containers/timeline_container').default;
const React = require('react');
const ReactDOM = require('react-dom');
const mountNode = document.getElementById('mastodon-timeline');
@@ -15,7 +13,7 @@ function loaded() {
}
function main() {
- const ready = require('themes/glitch/util/ready').default;
+ const ready = require('../mastodon/ready').default;
ready(loaded);
}
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index 21dc7898633..116632dea70 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -1,16 +1,5 @@
-// THIS IS THE `vanilla` THEME PACK FILE!!
-// IT'S HERE FOR UPSTREAM COMPATIBILITY!!
-// THE `glitch` PACK FILE IS IN `themes/glitch/index.js`!!
-
import loadPolyfills from '../mastodon/load_polyfills';
-// import default stylesheet with variables
-require('font-awesome/css/font-awesome.css');
-
-import '../styles/application.scss';
-
-require.context('../images/', true);
-
loadPolyfills().then(() => {
require('../mastodon/main').default();
}).catch(e => {
diff --git a/app/javascript/packs/common.js b/app/javascript/packs/common.js
index 96e6f4b16f4..5d42509c5f4 100644
--- a/app/javascript/packs/common.js
+++ b/app/javascript/packs/common.js
@@ -1,6 +1 @@
-import { start } from 'rails-ujs';
-import 'font-awesome/css/font-awesome.css';
-
-require.context('../images/', true);
-
-start();
+import 'styles/application.scss';
diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js
index 6adacad9848..3472af6c13b 100644
--- a/app/javascript/packs/public.js
+++ b/app/javascript/packs/public.js
@@ -1,33 +1,14 @@
-import loadPolyfills from 'themes/glitch/util/load_polyfills';
-import { processBio } from 'themes/glitch/util/bio_metadata';
-import ready from 'themes/glitch/util/ready';
-
-window.addEventListener('message', e => {
- const data = e.data || {};
-
- if (!window.parent || data.type !== 'setHeight') {
- return;
- }
-
- ready(() => {
- window.parent.postMessage({
- type: 'setHeight',
- id: data.id,
- height: document.getElementsByTagName('html')[0].scrollHeight,
- }, '*');
- });
-});
+import loadPolyfills from '../mastodon/load_polyfills';
+import ready from '../mastodon/ready';
function main() {
- const { length } = require('stringz');
const IntlRelativeFormat = require('intl-relativeformat').default;
- const { delegate } = require('rails-ujs');
- const emojify = require('../themes/glitch/util/emoji').default;
- const { getLocale } = require('mastodon/locales');
+ const emojify = require('../mastodon/features/emoji/emoji').default;
+ const { getLocale } = require('../mastodon/locales');
const { localeData } = getLocale();
- const VideoContainer = require('../themes/glitch/containers/video_container').default;
- const MediaGalleryContainer = require('../themes/glitch/containers/media_gallery_container').default;
- const CardContainer = require('../themes/glitch/containers/card_container').default;
+ const VideoContainer = require('../mastodon/containers/video_container').default;
+ const MediaGalleryContainer = require('../mastodon/containers/media_gallery_container').default;
+ const CardContainer = require('../mastodon/containers/card_container').default;
const React = require('react');
const ReactDOM = require('react-dom');
@@ -87,61 +68,6 @@ function main() {
ReactDOM.render(, content);
});
});
-
- delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
- if (button !== 0) {
- return true;
- }
- window.location.href = target.href;
- return false;
- });
-
- delegate(document, '.status__content__spoiler-link', 'click', ({ target }) => {
- const contentEl = target.parentNode.parentNode.querySelector('.e-content');
-
- if (contentEl.style.display === 'block') {
- contentEl.style.display = 'none';
- target.parentNode.style.marginBottom = 0;
- } else {
- contentEl.style.display = 'block';
- target.parentNode.style.marginBottom = null;
- }
-
- return false;
- });
-
- delegate(document, '.account_display_name', 'input', ({ target }) => {
- const nameCounter = document.querySelector('.name-counter');
-
- if (nameCounter) {
- nameCounter.textContent = 30 - length(target.value);
- }
- });
-
- delegate(document, '.account_note', 'input', ({ target }) => {
- const noteCounter = document.querySelector('.note-counter');
-
- if (noteCounter) {
- const noteWithoutMetadata = processBio(target.value).text;
- noteCounter.textContent = 500 - length(noteWithoutMetadata);
- }
- });
-
- delegate(document, '#account_avatar', 'change', ({ target }) => {
- const avatar = document.querySelector('.card.compact .avatar img');
- const [file] = target.files || [];
- const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;
-
- avatar.src = url;
- });
-
- delegate(document, '#account_header', 'change', ({ target }) => {
- const header = document.querySelector('.card.compact');
- const [file] = target.files || [];
- const url = file ? URL.createObjectURL(file) : header.dataset.originalSrc;
-
- header.style.backgroundImage = `url(${url})`;
- });
}
loadPolyfills().then(main).catch(error => {
diff --git a/app/javascript/packs/share.js b/app/javascript/packs/share.js
index 9cd95bcee51..e9580f648bf 100644
--- a/app/javascript/packs/share.js
+++ b/app/javascript/packs/share.js
@@ -1,9 +1,7 @@
-import loadPolyfills from 'themes/glitch/util/load_polyfills';
-
-require.context('../images/', true);
+import loadPolyfills from '../mastodon/load_polyfills';
function loaded() {
- const ComposeContainer = require('themes/glitch/containers/compose_container').default;
+ const ComposeContainer = require('../mastodon/containers/compose_container').default;
const React = require('react');
const ReactDOM = require('react-dom');
const mountNode = document.getElementById('mastodon-compose');
@@ -15,7 +13,7 @@ function loaded() {
}
function main() {
- const ready = require('themes/glitch/util/ready').default;
+ const ready = require('../mastodon/ready').default;
ready(loaded);
}
diff --git a/app/javascript/skins/vanilla/win95.scss b/app/javascript/skins/vanilla/win95.scss
new file mode 100644
index 00000000000..298f6ee9d51
--- /dev/null
+++ b/app/javascript/skins/vanilla/win95.scss
@@ -0,0 +1 @@
+@import 'styles/win95';
diff --git a/app/javascript/styles/common.scss b/app/javascript/styles/common.scss
deleted file mode 100644
index c1772e7ae19..00000000000
--- a/app/javascript/styles/common.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-// This makes our fonts available everywhere.
-
-@import 'fonts/roboto';
-@import 'fonts/roboto-mono';
-@import 'fonts/montserrat';
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index d72f53f3665..d80458af65f 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -2079,7 +2079,7 @@
.getting-started {
box-sizing: border-box;
padding-bottom: 235px;
- background: url('../images/mastodon-getting-started.png') no-repeat 0 100%;
+ background: url('~images/mastodon-getting-started.png') no-repeat 0 100%;
flex: 1 0 auto;
p {
@@ -2292,7 +2292,7 @@ button.icon-button.active i.fa-retweet {
justify-content: center;
& > div {
- background: url('../images/mastodon-not-found.png') no-repeat center -50px;
+ background: url('~images/mastodon-not-found.png') no-repeat center -50px;
padding-top: 210px;
width: 100%;
}
@@ -3177,7 +3177,7 @@ button.icon-button.active i.fa-retweet {
img,
canvas {
display: block;
- background: url('../images/void.png') repeat;
+ background: url('~images/void.png') repeat;
object-fit: contain;
}
@@ -3424,7 +3424,7 @@ button.icon-button.active i.fa-retweet {
}
.onboarding-modal__page-one__elephant-friend {
- background: url('../images/elephant-friend-1.png') no-repeat center center / contain;
+ background: url('~images/elephant-friend-1.png') no-repeat center center / contain;
width: 155px;
height: 193px;
margin-right: 15px;
diff --git a/app/javascript/styles/win95.scss b/app/javascript/styles/win95.scss
new file mode 100644
index 00000000000..d683218b060
--- /dev/null
+++ b/app/javascript/styles/win95.scss
@@ -0,0 +1,1655 @@
+// win95 theme from cybrespace.
+
+// Modified by kibi! to use webpack package syntax for urls (eg,
+// `url(~images/…)`) for easy importing into skins.
+
+$win95-bg: #bfbfbf;
+$win95-dark-grey: #404040;
+$win95-mid-grey: #808080;
+$win95-window-header: #00007f;
+$win95-tooltip-yellow: #ffffcc;
+$win95-blue: blue;
+
+$ui-base-lighter-color: $win95-dark-grey;
+$ui-highlight-color: $win95-window-header;
+
+@mixin win95-border-outset() {
+ border-left: 2px solid #efefef;
+ border-top: 2px solid #efefef;
+ border-right: 2px solid #404040;
+ border-bottom: 2px solid #404040;
+ border-radius:0px;
+}
+
+@mixin win95-outset() {
+ box-shadow: inset -1px -1px 0px #000000,
+ inset 1px 1px 0px #ffffff,
+ inset -2px -2px 0px #808080,
+ inset 2px 2px 0px #dfdfdf;
+ border-radius:0px;
+}
+
+@mixin win95-border-inset() {
+ border-left: 2px solid #404040;
+ border-top: 2px solid #404040;
+ border-right: 2px solid #efefef;
+ border-bottom: 2px solid #efefef;
+ border-radius:0px;
+}
+
+@mixin win95-border-slight-inset() {
+ border-left: 1px solid #404040;
+ border-top: 1px solid #404040;
+ border-right: 1px solid #efefef;
+ border-bottom: 1px solid #efefef;
+ border-radius:0px;
+}
+
+@mixin win95-inset() {
+ box-shadow: inset 1px 1px 0px #000000,
+ inset -1px -1px 0px #ffffff,
+ inset 2px 2px 0px #808080,
+ inset -2px -2px 0px #dfdfdf;
+ border-width:0px;
+ border-radius:0px;
+}
+
+
+@mixin win95-tab() {
+ box-shadow: inset -1px 0px 0px #000000,
+ inset 1px 0px 0px #ffffff,
+ inset 0px 1px 0px #ffffff,
+ inset 0px 2px 0px #dfdfdf,
+ inset -2px 0px 0px #808080,
+ inset 2px 0px 0px #dfdfdf;
+ border-radius:0px;
+ border-top-left-radius: 1px;
+ border-top-right-radius: 1px;
+}
+
+@mixin win95-reset() {
+ box-shadow: unset;
+}
+
+@font-face {
+ font-family:"premillenium";
+ src: url('~fonts/premillenium/MSSansSerif.ttf') format('truetype');
+}
+
+@import 'application';
+
+/* borrowed from cybrespace style: wider columns and full column width images */
+
+@media screen and (min-width: 1300px) {
+ .column {
+ flex-grow: 1 !important;
+ max-width: 400px;
+ }
+
+ .drawer {
+ width: 17%;
+ max-width: 400px;
+ min-width: 330px;
+ }
+}
+
+.media-gallery,
+.video-player {
+ max-height:30vh;
+ height:30vh !important;
+ position:relative;
+ margin-top:20px;
+ margin-left:-68px;
+ width: calc(100% + 80px) !important;
+ max-width: calc(100% + 80px);
+}
+
+.detailed-status .media-gallery,
+.detailed-status .video-player {
+ margin-left:-5px;
+ width: calc(100% + 9px);
+ max-width: calc(100% + 9px);
+}
+
+.video-player video {
+ transform: unset;
+ top: unset;
+}
+
+.detailed-status .media-spoiler,
+.status .media-spoiler {
+ height: 100%!important;
+ vertical-align: middle;
+}
+
+
+/* main win95 style */
+
+body {
+ font-size:13px;
+ font-family: "MS Sans Serif", "premillenium", sans-serif;
+ color:black;
+}
+
+.ui,
+.ui .columns-area,
+body.admin {
+ background: #008080;
+}
+
+.loading-bar {
+ height:5px;
+ background-color: #000080;
+}
+
+.tabs-bar {
+ background: $win95-bg;
+ @include win95-outset()
+ height: 30px;
+}
+
+.tabs-bar__link {
+ color:black;
+ border:2px outset $win95-bg;
+ border-top-width: 1px;
+ border-left-width: 1px;
+ margin:2px;
+ padding:3px;
+}
+
+.tabs-bar__link.active {
+ @include win95-inset();
+ color:black;
+}
+
+.tabs-bar__link:last-child::before {
+ content:"Start";
+ color:black;
+ font-weight:bold;
+ font-size:15px;
+ width:80%;
+ display:block;
+ position:absolute;
+ right:0px;
+}
+
+.tabs-bar__link:last-child {
+ position:relative;
+ flex-basis:60px !important;
+ font-size:0px;
+ color:$win95-bg;
+
+ background-image: url("~images/start.png");
+ background-repeat:no-repeat;
+ background-position:8%;
+ background-clip:padding-box;
+ background-size:auto 50%;
+}
+
+.drawer .drawer__inner {
+ overflow: visible;
+ height:inherit;
+}
+
+.drawer__pager {
+ overflow-y:auto;
+}
+
+.column {
+ max-height:100vh;
+}
+
+.column > .scrollable {
+ background: $win95-bg;
+ @include win95-border-outset()
+ border-top-width:0px;
+}
+
+.column-header__wrapper {
+ color:white;
+ font-weight:bold;
+ background:#7f7f7f;
+}
+
+.column-header {
+ padding:2px;
+ font-size:13px;
+ background:#7f7f7f;
+ @include win95-border-outset()
+ border-bottom-width:0px;
+ color:white;
+ font-weight:bold;
+}
+
+.column-header__wrapper.active {
+ background:$win95-window-header;
+}
+
+.column-header__wrapper.active::before {
+ display:none;
+}
+.column-header.active {
+ box-shadow:unset;
+ background:$win95-window-header;
+}
+
+.column-header.active .column-header__icon {
+ color:white;
+}
+
+.column-header__button {
+ background: $win95-bg;
+ color: black;
+ line-height:0px;
+ font-size:14px;
+ max-height:20px;
+ padding:0px 2px;
+ margin-top:2px;
+ @include win95-outset()
+}
+
+.column-header__button.active, .column-header__button.active:hover {
+ @include win95-inset();
+ background-color:#7f7f7f;
+}
+
+.column-header__back-button {
+ background: $win95-bg;
+ color: black;
+ padding:2px;
+ max-height:20px;
+ margin-top:2px;
+ @include win95-outset()
+ font-size:13px;
+ font-weight:bold;
+}
+
+.column-back-button {
+ background:$win95-bg;
+ color:black;
+ @include win95-outset()
+ padding:2px;
+ font-size:13px;
+ font-weight:bold;
+}
+
+.column-back-button--slim-button {
+ position:absolute;
+ top:-22px;
+ right:4px;
+ max-height:20px;
+ max-width:60px;
+ padding:0px 2px;
+}
+
+.column-back-button__icon {
+ font-size:11px;
+ margin-top:-3px;
+}
+
+.column-header__collapsible {
+ border-left:2px outset $win95-bg;
+ border-right:2px outset $win95-bg;
+}
+
+.column-header__collapsible-inner {
+ background:$win95-bg;
+ color:black;
+}
+
+.column-header__collapsible__extra {
+ color:black;
+}
+
+.column-header__collapsible__extra div[role="group"] {
+ border: 2px groove $win95-bg;
+ border-radius:4px;
+ margin-bottom:8px;
+ padding:4px;
+}
+
+.column-settings__section {
+ color:black;
+ font-weight:bold;
+ font-size:11px;
+ position:relative;
+ top: -12px;
+ left:4px;
+ background-color:$win95-bg;
+ display:inline-block;
+ padding:0px 4px;
+ margin-bottom:0px;
+}
+
+.setting-meta__label, .setting-toggle__label {
+ color:black;
+ font-weight:normal;
+}
+
+.setting-meta__label span:before {
+ content:"(";
+}
+.setting-meta__label span:after {
+ content:")";
+}
+
+.setting-toggle {
+ line-height:13px;
+}
+
+.react-toggle .react-toggle-track {
+ border-radius:0px;
+ background-color:white;
+ @include win95-border-inset();
+
+ width:12px;
+ height:12px;
+}
+
+.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
+ background-color:white;
+}
+
+.react-toggle .react-toggle-track-check {
+ left:2px;
+ transition:unset;
+}
+
+.react-toggle .react-toggle-track-check svg path {
+ fill: black;
+}
+
+.react-toggle .react-toggle-track-x {
+ display:none;
+}
+
+.react-toggle .react-toggle-thumb {
+ border-radius:0px;
+ display:none;
+}
+
+.text-btn {
+ background-color:$win95-bg;
+ @include win95-outset()
+ padding:4px;
+}
+
+.text-btn:hover {
+ text-decoration:none;
+ color:black;
+}
+
+.text-btn:active {
+ @include win95-inset();
+}
+
+.setting-text {
+ color:black;
+ background-color:white;
+ @include win95-inset();
+ font-size:13px;
+ padding:2px;
+}
+
+.setting-text:active, .setting-text:focus,
+.setting-text.light:active, .setting-text.light:focus {
+ color:black;
+ border-bottom:2px inset $win95-bg;
+}
+
+.column-header__setting-arrows .column-header__setting-btn {
+ padding:3px 10px;
+}
+
+.column-header__setting-arrows .column-header__setting-btn:last-child {
+ padding:3px 10px;
+}
+
+.missing-indicator {
+ background-color:$win95-bg;
+ color:black;
+ @include win95-outset()
+}
+
+.missing-indicator > div {
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAACXBIWXMAAC4jAAAuIwF4pT92AAAAF3pUWHRUaXRsZQAACJnLyy9Jyy/NSwEAD5IDblIFOhoAAAAXelRYdEF1dGhvcgAACJlLzijKz0vMAQALmgLoDsFj8gAAAQpJREFUOMuVlD0OwjAMhd2oQl04Axfo0IGBgYELcAY6cqQuSO0ZOEAZGBg6VKg74gwsEaoESRVHjusI8aQqzY8/PbtOEz1qkFSn2YevlaNOpLMJh2DwvixhuXtOa6/LCh51DUMEFkAsgAZD207Doin8mQ562JpRE5CHBAAhmIqD1L8AqzUUUJkxc6kr3AgAJ+NuvIWRdk7WcrKl0AUqcIBBHOiEbpS4m27mIL5Onfg3k0rgggeQuS2sDOGSahKR+glgqaGLgUJs951NN1q9D72cQqQWR9cr3sm9YcEssEuz6eEuZh2bu0aSOhQ1MBezu2O/+TVSvEFII3qLsZWrSA2AAUQIh1HpyP/kC++zjVSMj6ntAAAAAElFTkSuQmCC')
+ no-repeat;
+ background-position:center center;
+}
+
+.empty-column-indicator,
+.error-column {
+ background: $win95-bg;
+ color: black;
+}
+
+.status__wrapper {
+ border: 2px groove $win95-bg;
+ margin:4px;
+}
+
+.status {
+ @include win95-border-slight-inset();
+ background-color:white;
+ margin:4px;
+ padding-bottom:40px;
+ margin-bottom:8px;
+}
+
+.status.status-direct {
+ background-color:$win95-bg;
+}
+
+.status__content {
+ font-size:13px;
+}
+
+.status.light .status__relative-time,
+.status.light .display-name span {
+ color: #7f7f7f;
+}
+
+.status__action-bar {
+ box-sizing:border-box;
+ position:absolute;
+ bottom:-1px;
+ left:-1px;
+ background:$win95-bg;
+ width:calc(100% + 2px);
+ padding-left:10px;
+ padding: 4px 2px;
+ padding-bottom:4px;
+ border-bottom:2px groove $win95-bg;
+ border-top:1px outset $win95-bg;
+ text-align: right;
+}
+
+.status__wrapper .status__action-bar {
+ border-bottom-width:0px;
+}
+
+.status__action-bar-button {
+ float:right;
+}
+
+.status__action-bar-dropdown {
+ margin-left:auto;
+ margin-right:10px;
+
+ .icon-button {
+ min-width:28px;
+ }
+}
+.status.light .status__content a {
+ color:blue;
+}
+
+.focusable:focus {
+ background: $win95-bg;
+ .detailed-status__action-bar {
+ background: $win95-bg;
+ }
+
+ .status, .detailed-status {
+ background: white;
+ outline:2px dotted $win95-mid-grey;
+ }
+}
+
+.dropdown__trigger.icon-button {
+ padding-right:6px;
+}
+
+.detailed-status__action-bar-dropdown .icon-button {
+ min-width:28px;
+}
+
+.detailed-status {
+ background:white;
+ background-clip:padding-box;
+ margin:4px;
+ border: 2px groove $win95-bg;
+ padding:4px;
+}
+
+.detailed-status__display-name {
+ color:#7f7f7f;
+}
+
+.detailed-status__display-name strong {
+ color:black;
+ font-weight:bold;
+}
+.account__avatar,
+.account__avatar-overlay-base,
+.account__header__avatar,
+.account__avatar-overlay-overlay {
+ @include win95-border-slight-inset();
+ clip-path:none;
+ filter: saturate(1.8) brightness(1.1);
+}
+
+.detailed-status__action-bar {
+ background-color:$win95-bg;
+ border:0px;
+ border-bottom:2px groove $win95-bg;
+ margin-bottom:8px;
+ justify-items:left;
+ padding-left:4px;
+}
+.icon-button {
+ background:$win95-bg;
+ @include win95-border-outset()
+ padding:0px 0px 0px 0px;
+ margin-right:4px;
+
+ color:#3f3f3f;
+ &.inverted, &:hover, &.inverted:hover, &:active, &:focus {
+ color:#3f3f3f;
+ }
+}
+
+.icon-button:active {
+ @include win95-border-inset();
+}
+
+.status__action-bar > .icon-button {
+ padding:0px 15px 0px 0px;
+ min-width:25px;
+}
+
+.icon-button.star-icon,
+.icon-button.star-icon:active {
+ background:transparent;
+ border:none;
+}
+
+.icon-button.star-icon.active {
+ color: $gold-star;
+ &:active, &:hover, &:focus {
+ color: $gold-star;
+ }
+}
+
+.icon-button.star-icon > i {
+ background:$win95-bg;
+ @include win95-border-outset()
+ padding-bottom:3px;
+}
+
+.icon-button.star-icon:active > i {
+ @include win95-border-inset();
+}
+
+.text-icon-button {
+ color:$win95-dark-grey;
+}
+
+.detailed-status__action-bar-dropdown {
+ margin-left:auto;
+ justify-content:right;
+ padding-right:16px;
+}
+
+.detailed-status__button {
+ flex:0 0 auto;
+}
+
+.detailed-status__button .icon-button {
+ padding-left:2px;
+ padding-right:25px;
+}
+
+.status-card {
+ border-radius:0px;
+ background:white;
+ border: 1px solid black;
+ color:black;
+}
+
+.status-card:hover {
+ background-color:white;
+}
+
+.status-card__title {
+ color:blue;
+ text-decoration:underline;
+ font-weight:bold;
+}
+
+.load-more {
+ width:auto;
+ margin:5px auto;
+ background: $win95-bg;
+ @include win95-outset();
+ color:black;
+ padding: 2px 5px;
+
+ &:hover {
+ background: $win95-bg;
+ color:black;
+ }
+}
+
+.status-card__description {
+ color:black;
+}
+
+.account__display-name strong, .status__display-name strong {
+ color:black;
+ font-weight:bold;
+}
+
+.account .account__display-name {
+ color:black;
+}
+
+.account {
+ border-bottom: 2px groove $win95-bg;
+}
+
+.reply-indicator__content .status__content__spoiler-link, .status__content .status__content__spoiler-link {
+ background:$win95-bg;
+ @include win95-outset()
+}
+
+.reply-indicator__content .status__content__spoiler-link:hover, .status__content .status__content__spoiler-link:hover {
+ background:$win95-bg;
+}
+
+.reply-indicator__content .status__content__spoiler-link:active, .status__content .status__content__spoiler-link:active {
+ @include win95-inset();
+}
+
+.reply-indicator__content a, .status__content a {
+ color:blue;
+}
+
+.notification {
+ border: 2px groove $win95-bg;
+ margin:4px;
+}
+
+.notification__message {
+ color:black;
+ font-size:13px;
+}
+
+.notification__display-name {
+ font-weight:bold;
+}
+
+
+.drawer__header {
+ background: $win95-bg;
+ @include win95-border-outset()
+ justify-content:left;
+ margin-bottom:0px;
+ padding-bottom:2px;
+ border-bottom:2px groove $win95-bg;
+}
+
+.drawer__tab {
+ color:black;
+ @include win95-outset()
+ padding:5px;
+ margin:2px;
+ flex: 0 0 auto;
+}
+
+.drawer__tab:first-child::before {
+ content:"Start";
+ color:black;
+ font-weight:bold;
+ font-size:15px;
+ width:80%;
+ display:block;
+ position:absolute;
+ right:0px;
+
+}
+
+.drawer__tab:first-child {
+ position:relative;
+ padding:5px 15px;
+ width:40px;
+ font-size:0px;
+ color:$win95-bg;
+
+ background-image: url("~images/start.png");
+ background-repeat:no-repeat;
+ background-position:8%;
+ background-clip:padding-box;
+ background-size:auto 50%;
+}
+
+.drawer__header a:hover {
+ background-color:transparent;
+}
+
+.drawer__header a:first-child:hover {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAOCAIAAACpTQvdAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAF3pUWHRBdXRob3IAAAiZS84oys9LzAEAC5oC6A7BY/IAAACWSURBVCiRhVJJDsQgDEuqOfRZ7a1P5gbP4uaJaEjTADMWQhHYjlk4p0wLnNdptdF4KvBUDyGzVwc2xO+uKtH+1o0ytEEmqFpuxlvFCGCxKbNIT56QCi2MzaA/2Mz+mERSOeqzJG2RUxkjdTabgPtFoZ1bZxcKvgPcLZVufAyR9Ni8v5dWDzfFx0giC1RvZFv6l35QQ/Mvv39XXgGzQpoAAAAASUVORK5CYII=");
+ background-repeat:no-repeat;
+ background-position:8%;
+ background-clip:padding-box;
+ background-size:auto 50%;
+ transition:unset;
+}
+
+.drawer__tab:first-child {
+
+}
+
+.search {
+ background:$win95-bg;
+ padding-top:2px;
+ padding:2px;
+ border:2px outset $win95-bg;
+ border-top-width:0px;
+ border-bottom: 2px groove $win95-bg;
+ margin-bottom:0px;
+}
+
+.search input {
+ background-color:white;
+ color:black;
+ @include win95-border-slight-inset();
+}
+
+.search__input:focus {
+ background-color:white;
+}
+
+.search-popout {
+ box-shadow: unset;
+ color:black;
+ border-radius:0px;
+ background-color:$win95-tooltip-yellow;
+ border:1px solid black;
+
+ h4 {
+ color:black;
+ text-transform: none;
+ font-weight:bold;
+ }
+}
+
+.search-results__header {
+ background-color: $win95-bg;
+ color:black;
+ border-bottom:2px groove $win95-bg;
+}
+
+.search-results__hashtag {
+ color:blue;
+}
+
+.search-results__section .account:hover,
+.search-results__section .account:hover .account__display-name,
+.search-results__section .account:hover .account__display-name strong,
+.search-results__section .search-results__hashtag:hover {
+ background-color:$win95-window-header;
+ color:white;
+}
+
+.search__icon .fa {
+ color:#808080;
+
+ &.active {
+ opacity:1.0;
+ }
+
+ &:hover {
+ color: #808080;
+ }
+}
+
+.drawer__inner,
+.drawer__inner.darker {
+ background-color:$win95-bg;
+ border: 2px outset $win95-bg;
+ border-top-width:0px;
+}
+
+.navigation-bar {
+ color:black;
+}
+
+.navigation-bar strong {
+ color:black;
+ font-weight:bold;
+}
+
+.autosuggest-textarea__textarea, .spoiler-input__input {
+ border-radius:0px;
+ @include win95-border-slight-inset();
+}
+
+.autosuggest-textarea__textarea {
+ border-bottom:0px;
+}
+
+.compose-form__uploads-wrapper {
+ border-radius:0px;
+ border-bottom:1px inset $win95-bg;
+ border-top-width:0px;
+}
+
+.compose-form__upload-wrapper {
+ border-left:1px inset $win95-bg;
+ border-right:1px inset $win95-bg;
+}
+
+.compose-form__buttons {
+ background-color:$win95-bg;
+ border-radius:0px;
+ box-shadow:unset;
+ border:2px groove $win95-bg;
+ margin-top:4px;
+ padding:4px 8px;
+}
+
+.privacy-dropdown.active
+.privacy-dropdown__value {
+ background: $win95-bg;
+ box-shadow:unset;
+}
+
+.privacy-dropdown__option.active, .privacy-dropdown__option:hover,
+.privacy-dropdown__option.active:hover {
+ background:$win95-window-header;
+}
+
+.privacy-dropdown.active .privacy-dropdown__dropdown {
+ box-shadow:unset;
+ color:black;
+ @include win95-outset()
+ background: $win95-bg;
+}
+
+.privacy-dropdown__option__content {
+ color:black;
+}
+
+.privacy-dropdown__option__content strong {
+ font-weight:bold;
+}
+
+.compose-form__warning::before {
+ content:"Tip:";
+ font-weight:bold;
+ display:block;
+ position:absolute;
+ top:-10px;
+ background-color:$win95-bg;
+ font-size:11px;
+ padding: 0px 5px;
+}
+
+.compose-form__warning {
+ position:relative;
+ box-shadow:unset;
+ border:2px groove $win95-bg;
+ background-color:$win95-bg;
+ color:black;
+}
+
+.compose-form__warning a {
+ color:blue;
+}
+
+.compose-form__warning strong {
+ color:black;
+ text-decoration:underline;
+}
+
+.compose-form__buttons button.active:last-child {
+ @include win95-border-inset();
+ background: #dfdfdf;
+ color:#7f7f7f;
+}
+
+.compose-form__upload-thumbnail {
+ border-radius:0px;
+ border:2px groove $win95-bg;
+ background-color:$win95-bg;
+ padding:2px;
+ box-sizing:border-box;
+}
+
+.compose-form__upload-thumbnail .icon-button {
+ max-width:20px;
+ max-height:20px;
+ line-height:10px !important;
+}
+
+.compose-form__upload-thumbnail .icon-button::before {
+ content:"X";
+ font-size:13px;
+ font-weight:bold;
+ color:black;
+}
+
+.compose-form__upload-thumbnail .icon-button i {
+ display:none;
+}
+
+.emoji-dialog.with-search {
+ box-shadow:unset;
+ border-radius:0px;
+ background-color:$win95-bg;
+ border:1px solid black;
+ box-sizing:content-box;
+
+}
+
+.emoji-dialog .emoji-search {
+ color:black;
+ background-color:white;
+ border-radius:0px;
+ @include win95-inset();
+}
+
+.emoji-dialog .emoji-search-wrapper {
+ border-bottom:2px groove $win95-bg;
+}
+
+.emoji-dialog .emoji-category-title {
+ color:black;
+ font-weight:bold;
+}
+
+.reply-indicator {
+ background-color:$win95-bg;
+ border-radius:3px;
+ border:2px groove $win95-bg;
+}
+
+.button {
+ background-color:$win95-bg;
+ @include win95-outset()
+ border-radius:0px;
+ color:black;
+ font-weight:bold;
+
+ &:hover, &:focus, &:disabled {
+ background-color:$win95-bg;
+ }
+
+ &:active {
+ @include win95-inset();
+ }
+
+ &:disabled {
+ color: #808080;
+ text-shadow: 1px 1px 0px #efefef;
+
+ &:active {
+ @include win95-outset();
+ }
+ }
+
+}
+
+#Getting-started {
+ background-color:$win95-bg;
+ @include win95-inset();
+ border-bottom-width:0px;
+}
+
+#Getting-started::before {
+ content:"Start";
+ color:black;
+ font-weight:bold;
+ font-size:15px;
+ width:80%;
+ text-align:center;
+ display:block;
+ position:absolute;
+ right:2px;
+}
+
+#Getting-started {
+ position:relative;
+ padding:5px 15px;
+ width:60px;
+ font-size:0px;
+ color:$win95-bg;
+
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAOCAIAAACpTQvdAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAF3pUWHRBdXRob3IAAAiZS84oys9LzAEAC5oC6A7BY/IAAACWSURBVCiRhVJJDsQgDEuqOfRZ7a1P5gbP4uaJaEjTADMWQhHYjlk4p0wLnNdptdF4KvBUDyGzVwc2xO+uKtH+1o0ytEEmqFpuxlvFCGCxKbNIT56QCi2MzaA/2Mz+mERSOeqzJG2RUxkjdTabgPtFoZ1bZxcKvgPcLZVufAyR9Ni8v5dWDzfFx0giC1RvZFv6l35QQ/Mvv39XXgGzQpoAAAAASUVORK5CYII=");
+ background-repeat:no-repeat;
+ background-position:8%;
+ background-clip:padding-box;
+ background-size:auto 50%;
+}
+
+.column-subheading {
+ background-color:$win95-bg;
+ color:black;
+ font-size:0px;
+ border-bottom: 2px groove $win95-bg;
+ padding:0px;
+ margin:0px;
+}
+
+.column-link {
+ background-color:transparent;
+ background-size:32px 32px;
+ background-repeat:no-repeat;
+ background-position: 36px 50%;
+ color:black;
+ padding-left:40px;
+
+ &:hover {
+ background-color: $win95-window-header;
+ background-size:32px 32px;
+ background-repeat:no-repeat;
+ background-position: 36px 50%;
+ color:white;
+ }
+
+ i {
+ font-size: 0px;
+ width:32px;
+ }
+}
+
+.column-link[href="/web/timelines/public"] {
+ background-image: url("~images/icon_public.png");
+ &:hover { background-image: url("~images/icon_public.png"); }
+}
+.column-link[href="/web/timelines/public/local"] {
+ background-image: url("~images/icon_local.png");
+ &:hover { background-image: url("~images/icon_local.png"); }
+}
+.column-link[href="/web/pinned"] {
+ background-image: url("~images/icon_pin.png");
+ &:hover { background-image: url("~images/icon_pin.png"); }
+}
+.column-link[href="/web/favourites"] {
+ background-image: url("~images/icon_likes.png");
+ &:hover { background-image: url("~images/icon_likes.png"); }
+}
+.column-link[href="/web/blocks"] {
+ background-image: url("~images/icon_blocks.png");
+ &:hover { background-image: url("~images/icon_blocks.png"); }
+}
+.column-link[href="/web/mutes"] {
+ background-image: url("~images/icon_mutes.png");
+ &:hover { background-image: url("~images/icon_mutes.png"); }
+}
+.column-link[href="/settings/preferences"] {
+ background-image: url("~images/icon_settings.png");
+ &:hover { background-image: url("~images/icon_settings.png"); }
+}
+.column-link[href="/about/more"] {
+ background-image: url("~images/icon_about.png");
+ &:hover { background-image: url("~images/icon_about.png"); }
+}
+.column-link[href="/auth/sign_out"] {
+ background-image: url("~images/icon_logout.png");
+ &:hover { background-image: url("~images/icon_logout.png"); }
+}
+
+.getting-started__footer {
+ display:none;
+}
+
+.getting-started__wrapper::before {
+ content:"Mastodon 95";
+ font-weight:bold;
+ font-size:23px;
+ color:white;
+ line-height:30px;
+ padding-left:20px;
+ padding-right:40px;
+
+ left:0px;
+ bottom:-30px;
+ display:block;
+ position:absolute;
+ background-color:#7f7f7f;
+ width:200%;
+ height:30px;
+
+ -ms-transform: rotate(-90deg);
+
+ -webkit-transform: rotate(-90deg);
+ transform: rotate(-90deg);
+ transform-origin:top left;
+}
+
+.getting-started__wrapper {
+ @include win95-border-outset()
+ background-color:$win95-bg;
+}
+
+.account__header {
+ background-color:#7f7f7f;
+}
+
+.account__header .account__header__content {
+ color:white;
+}
+
+.account__action-bar__tab > span {
+ color:black;
+ font-weight:bold;
+}
+
+.account__action-bar__tab strong {
+ color:black;
+}
+
+.account__action-bar {
+ border: unset;
+}
+
+.account__action-bar__tab {
+ border: 1px outset $win95-bg;
+}
+
+.account__action-bar__tab:active {
+ @include win95-inset();
+}
+
+.dropdown--active .dropdown__content > ul,
+.dropdown-menu {
+ background:$win95-tooltip-yellow;
+ border-radius:0px;
+ border:1px solid black;
+ box-shadow:unset;
+}
+
+.dropdown-menu a {
+ background-color:transparent;
+}
+
+.dropdown--active::after {
+ display:none;
+}
+
+.dropdown--active .icon-button {
+ color:black;
+ @include win95-inset();
+}
+
+.dropdown--active .dropdown__content > ul > li > a {
+ background:transparent;
+}
+
+.dropdown--active .dropdown__content > ul > li > a:hover {
+ background:transparent;
+ color:black;
+ text-decoration:underline;
+}
+
+.dropdown__sep,
+.dropdown-menu__separator
+{
+ border-color:#7f7f7f;
+}
+
+.detailed-status__action-bar-dropdown .dropdown--active .dropdown__content.dropdown__left {
+ left:unset;
+}
+
+.dropdown > .icon-button, .detailed-status__button > .icon-button,
+.status__action-bar > .icon-button, .star-icon i {
+ /* i don't know what's going on with the inline
+ styles someone should look at the react code */
+ height: 25px !important;
+ width: 28px !important;
+ box-sizing: border-box;
+}
+
+.status__action-bar-button .fa-floppy-o {
+ padding-top: 2px;
+}
+
+.status__action-bar-dropdown {
+ position: relative;
+ top: -3px;
+}
+
+.detailed-status__action-bar-dropdown .dropdown {
+ position: relative;
+ top: -4px;
+}
+
+.notification .status__action-bar {
+ border-bottom: none;
+}
+
+.notification .status {
+ margin-bottom: 4px;
+}
+
+.status__wrapper .status {
+ margin-bottom: 3px;
+}
+
+.status__wrapper {
+ margin-bottom: 8px;
+}
+
+.icon-button .fa-retweet {
+ position: relative;
+ top: -1px;
+}
+
+.embed-modal, .error-modal, .onboarding-modal,
+.actions-modal, .boost-modal, .confirmation-modal, .report-modal {
+ @include win95-outset()
+ background:$win95-bg;
+}
+
+.actions-modal::before,
+.boost-modal::before,
+.confirmation-modal::before,
+.report-modal::before {
+ content: "Confirmation";
+ display:block;
+ background:$win95-window-header;
+ color:white;
+ font-weight:bold;
+ padding-left:2px;
+}
+
+.boost-modal::before {
+ content: "Boost confirmation";
+}
+
+.boost-modal__action-bar > div > span:before {
+ content: "Tip: ";
+ font-weight:bold;
+}
+
+.boost-modal__action-bar, .confirmation-modal__action-bar, .report-modal__action-bar {
+ background:$win95-bg;
+ margin-top:-15px;
+}
+
+.embed-modal h4, .error-modal h4, .onboarding-modal h4 {
+ background:$win95-window-header;
+ color:white;
+ font-weight:bold;
+ padding:2px;
+ font-size:13px;
+ text-align:left;
+}
+
+.confirmation-modal__action-bar {
+ .confirmation-modal__cancel-button {
+ color:black;
+
+ &:active,
+ &:focus,
+ &:hover {
+ color:black;
+ }
+
+ &:active {
+ @include win95-inset();
+ }
+ }
+}
+
+.embed-modal .embed-modal__container .embed-modal__html,
+.embed-modal .embed-modal__container .embed-modal__html:focus {
+ background:white;
+ color:black;
+ @include win95-inset();
+}
+
+.modal-root__overlay,
+.account__header > div {
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFnpUWHRUaXRsZQAACJnLzU9JzElKBwALgwLXaCRlPwAAABd6VFh0QXV0aG9yAAAImUvOKMrPS8wBAAuaAugOwWPyAAAAEUlEQVQImWNgYGD4z4AE/gMADwMB/414xEUAAAAASUVORK5CYII=');
+}
+
+
+.admin-wrapper::before {
+ position:absolute;
+ top:0px;
+ content:"Control Panel";
+ color:white;
+ background-color:$win95-window-header;
+ font-size:13px;
+ font-weight:bold;
+ width:calc(100%);
+ margin: 2px;
+ display:block;
+ padding:2px;
+ padding-left:22px;
+ box-sizing:border-box;
+}
+
+.admin-wrapper {
+ position:relative;
+ background: $win95-bg;
+ @include win95-outset()
+ width:70vw;
+ height:80vh;
+ margin:10vh auto;
+ color: black;
+ padding-top:24px;
+ flex-direction:column;
+ overflow:hidden;
+}
+
+@media screen and (max-width: 1120px) {
+ .admin-wrapper {
+ width:90vw;
+ height:95vh;
+ margin:2.5vh auto;
+ }
+}
+
+@media screen and (max-width: 740px) {
+ .admin-wrapper {
+ width:100vw;
+ height:95vh;
+ height:calc(100vh - 24px);
+ margin:0px 0px 0px 0px;
+ }
+}
+
+.admin-wrapper .sidebar-wrapper {
+ position:static;
+ height:auto;
+ flex: 0 0 auto;
+ margin:2px;
+}
+
+.admin-wrapper .content-wrapper {
+ flex: 1 1 auto;
+ width:calc(100% - 20px);
+ @include win95-border-outset()
+ position:relative;
+ margin-left:10px;
+ margin-right:10px;
+ margin-bottom:40px;
+ box-sizing:border-box;
+}
+
+.admin-wrapper .content {
+ background-color: $win95-bg;
+ width: 100%;
+ max-width:100%;
+ min-height:100%;
+ box-sizing:border-box;
+ position:relative;
+}
+
+.admin-wrapper .sidebar {
+ position:static;
+ background: $win95-bg;
+ color:black;
+ width: 100%;
+ height:auto;
+ padding-bottom: 20px;
+}
+
+.admin-wrapper .sidebar .logo {
+ position:absolute;
+ top:2px;
+ left:4px;
+ width:18px;
+ height:18px;
+ margin:0px;
+}
+
+.admin-wrapper .sidebar > ul {
+ background: $win95-bg;
+ margin:0px;
+ margin-left:8px;
+ color:black;
+
+ & > li {
+ display:inline-block;
+
+ settings,
+ admin {
+ padding:2px;
+ border: 0px solid transparent;
+ }
+
+ logout {
+ position:absolute;
+ @include win95-outset();
+ right:12px;
+ bottom:10px;
+ }
+
+ web {
+ display:inline-block;
+ @include win95-outset();
+ position:absolute;
+ left: 12px;
+ bottom: 10px;
+ }
+
+ & > a {
+ display:inline-block;
+ @include win95-tab();
+ padding:2px 5px;
+ margin:0px;
+ color:black;
+ vertical-align:baseline;
+
+ &.selected {
+ background: $win95-bg;
+ color:black;
+ padding-top: 4px;
+ padding-bottom:4px;
+ }
+
+ &:hover {
+ background: $win95-bg;
+ color:black;
+ }
+ }
+
+ & > ul {
+ width:calc(100% - 20px);
+ background: transparent;
+ position:absolute;
+ left: 10px;
+ top:54px;
+ z-index:3;
+
+ & > li {
+ background: $win95-bg;
+ display: inline-block;
+ vertical-align:baseline;
+
+ & > a {
+ background: $win95-bg;
+ @include win95-tab();
+ color:black;
+ padding:2px 5px;
+ position:relative;
+ z-index:3;
+
+ &.selected {
+ background: $win95-bg;
+ color:black;
+ padding-bottom:4px;
+ padding-top: 4px;
+ padding-right:7px;
+ margin-left:-2px;
+ margin-right:-2px;
+ position:relative;
+ z-index:4;
+
+ &:first-child {
+ margin-left:0px;
+ }
+
+ &:hover {
+ background: transparent;
+ color:black;
+ }
+ }
+
+ &:hover {
+ background: $win95-bg;
+ color:black;
+ }
+ }
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 1520px) {
+ .admin-wrapper .sidebar > ul > li > ul {
+ max-width:1000px;
+ }
+
+ .admin-wrapper .sidebar {
+ padding-bottom: 45px;
+ }
+}
+
+@media screen and (max-width: 600px) {
+ .admin-wrapper .sidebar > ul > li > ul {
+ max-width:500px;
+ }
+
+ .admin-wrapper {
+ .sidebar {
+ padding:0px;
+ padding-bottom: 70px;
+ width: 100%;
+ height: auto;
+ }
+ .content-wrapper {
+ overflow:auto;
+ height:80%;
+ height:calc(100% - 150px);
+ }
+ }
+}
+
+.flash-message {
+ background-color:$win95-tooltip-yellow;
+ color:black;
+ border:1px solid black;
+ border-radius:0px;
+ position:absolute;
+ top:0px;
+ left:0px;
+ width:100%;
+}
+
+.admin-wrapper table {
+ background-color: white;
+ @include win95-border-slight-inset();
+}
+
+.admin-wrapper .content h2,
+.simple_form .input.with_label .label_input > label,
+.admin-wrapper .content h6,
+.admin-wrapper .content > p,
+.admin-wrapper .content .muted-hint,
+.simple_form span.hint,
+.simple_form h4,
+.simple_form .check_boxes .checkbox label,
+.simple_form .input.with_label.boolean .label_input > label,
+.filters .filter-subset a,
+.simple_form .input.radio_buttons .radio label,
+a.table-action-link,
+a.table-action-link:hover,
+.simple_form .input.with_block_label > label,
+.simple_form p.hint {
+ color:black;
+}
+
+.table > tbody > tr:nth-child(2n+1) > td,
+.table > tbody > tr:nth-child(2n+1) > th {
+ background-color:white;
+}
+
+.simple_form input[type=text],
+.simple_form input[type=number],
+.simple_form input[type=email],
+.simple_form input[type=password],
+.simple_form textarea {
+ color:black;
+ background-color:white;
+ @include win95-border-slight-inset();
+
+ &:active, &:focus {
+ background-color:white;
+ }
+}
+
+.simple_form button,
+.simple_form .button,
+.simple_form .block-button
+{
+ background: $win95-bg;
+ @include win95-outset()
+ color:black;
+ font-weight: normal;
+
+ &:hover {
+ background: $win95-bg;
+ }
+}
+
+.simple_form .warning, .table-form .warning
+{
+ background: $win95-tooltip-yellow;
+ color:black;
+ box-shadow: unset;
+ text-shadow:unset;
+ border:1px solid black;
+
+ a {
+ color: blue;
+ text-decoration:underline;
+ }
+}
+
+.simple_form button.negative,
+.simple_form .button.negative,
+.simple_form .block-button.negative
+{
+ background: $win95-bg;
+}
+
+.filters .filter-subset {
+ border: 2px groove $win95-bg;
+ padding:2px;
+}
+
+.filters .filter-subset a::before {
+ content: "";
+ background-color:white;
+ border-radius:50%;
+ border:2px solid black;
+ border-top-color:#7f7f7f;
+ border-left-color:#7f7f7f;
+ border-bottom-color:#f5f5f5;
+ border-right-color:#f5f5f5;
+ width:12px;
+ height:12px;
+ display:inline-block;
+ vertical-align:middle;
+ margin-right:2px;
+}
+
+.filters .filter-subset a.selected::before {
+ background-color:black;
+ box-shadow: inset 0 0 0 3px white;
+}
+
+.filters .filter-subset a,
+.filters .filter-subset a:hover,
+.filters .filter-subset a.selected {
+ color:black;
+ border-bottom: 0px solid transparent;
+}
+
diff --git a/app/javascript/themes/glitch/features/generic_not_found/index.js b/app/javascript/themes/glitch/features/generic_not_found/index.js
deleted file mode 100644
index ccd2b87b2f8..00000000000
--- a/app/javascript/themes/glitch/features/generic_not_found/index.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import Column from 'themes/glitch/features/ui/components/column';
-import MissingIndicator from 'themes/glitch/components/missing_indicator';
-
-const GenericNotFound = () => (
-
-
-
-);
-
-export default GenericNotFound;
diff --git a/app/javascript/themes/glitch/features/standalone/compose/index.js b/app/javascript/themes/glitch/features/standalone/compose/index.js
deleted file mode 100644
index 8a8118178b2..00000000000
--- a/app/javascript/themes/glitch/features/standalone/compose/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import ComposeFormContainer from 'themes/glitch/features/compose/containers/compose_form_container';
-import NotificationsContainer from 'themes/glitch/features/ui/containers/notifications_container';
-import LoadingBarContainer from 'themes/glitch/features/ui/containers/loading_bar_container';
-import ModalContainer from 'themes/glitch/features/ui/containers/modal_container';
-
-export default class Compose extends React.PureComponent {
-
- render () {
- return (
-
-
-
-
-
-
- );
- }
-
-}
diff --git a/app/javascript/themes/glitch/index.js b/app/javascript/themes/glitch/index.js
deleted file mode 100644
index 407e1f767d6..00000000000
--- a/app/javascript/themes/glitch/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import loadPolyfills from './util/load_polyfills';
-
-// import default stylesheet with variables
-require('font-awesome/css/font-awesome.css');
-
-import './styles/index.scss';
-
-require.context('../../images/', true);
-
-loadPolyfills().then(() => {
- require('./util/main').default();
-}).catch(e => {
- console.error(e);
-});
diff --git a/app/javascript/themes/glitch/theme.yml b/app/javascript/themes/glitch/theme.yml
deleted file mode 100644
index 49fba8f40cf..00000000000
--- a/app/javascript/themes/glitch/theme.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-# (REQUIRED) The location of the pack file inside `pack_directory`.
-pack: index.js
-
-# (OPTIONAL) The directory which contains the pack file.
-# Defaults to the theme directory (`app/javascript/themes/[theme]`),
-# but in the case of the vanilla Mastodon theme the pack file is
-# somewhere else.
-# pack_directory: app/javascript/packs
-
-# (OPTIONAL) Additional javascript resources to preload, for use with
-# lazy-loaded components. It is **STRONGLY RECOMMENDED** that you
-# derive these pathnames from `themes/[your-theme]` to ensure that
-# they stay unique. (Of course, vanilla doesn't do this ^^;;)
-preload:
-- themes/glitch/async/getting_started
-- themes/glitch/async/compose
-- themes/glitch/async/home_timeline
-- themes/glitch/async/notifications
diff --git a/app/javascript/themes/glitch/util/async-components.js b/app/javascript/themes/glitch/util/async-components.js
deleted file mode 100644
index 91e85fed557..00000000000
--- a/app/javascript/themes/glitch/util/async-components.js
+++ /dev/null
@@ -1,115 +0,0 @@
-export function EmojiPicker () {
- return import(/* webpackChunkName: "themes/glitch/async/emoji_picker" */'themes/glitch/util/emoji/emoji_picker');
-}
-
-export function Compose () {
- return import(/* webpackChunkName: "themes/glitch/async/compose" */'themes/glitch/features/compose');
-}
-
-export function Notifications () {
- return import(/* webpackChunkName: "themes/glitch/async/notifications" */'themes/glitch/features/notifications');
-}
-
-export function HomeTimeline () {
- return import(/* webpackChunkName: "themes/glitch/async/home_timeline" */'themes/glitch/features/home_timeline');
-}
-
-export function PublicTimeline () {
- return import(/* webpackChunkName: "themes/glitch/async/public_timeline" */'themes/glitch/features/public_timeline');
-}
-
-export function CommunityTimeline () {
- return import(/* webpackChunkName: "themes/glitch/async/community_timeline" */'themes/glitch/features/community_timeline');
-}
-
-export function HashtagTimeline () {
- return import(/* webpackChunkName: "themes/glitch/async/hashtag_timeline" */'themes/glitch/features/hashtag_timeline');
-}
-
-export function DirectTimeline() {
- return import(/* webpackChunkName: "themes/glitch/async/direct_timeline" */'themes/glitch/features/direct_timeline');
-}
-
-export function Status () {
- return import(/* webpackChunkName: "themes/glitch/async/status" */'themes/glitch/features/status');
-}
-
-export function GettingStarted () {
- return import(/* webpackChunkName: "themes/glitch/async/getting_started" */'themes/glitch/features/getting_started');
-}
-
-export function PinnedStatuses () {
- return import(/* webpackChunkName: "themes/glitch/async/pinned_statuses" */'themes/glitch/features/pinned_statuses');
-}
-
-export function AccountTimeline () {
- return import(/* webpackChunkName: "themes/glitch/async/account_timeline" */'themes/glitch/features/account_timeline');
-}
-
-export function AccountGallery () {
- return import(/* webpackChunkName: "themes/glitch/async/account_gallery" */'themes/glitch/features/account_gallery');
-}
-
-export function Followers () {
- return import(/* webpackChunkName: "themes/glitch/async/followers" */'themes/glitch/features/followers');
-}
-
-export function Following () {
- return import(/* webpackChunkName: "themes/glitch/async/following" */'themes/glitch/features/following');
-}
-
-export function Reblogs () {
- return import(/* webpackChunkName: "themes/glitch/async/reblogs" */'themes/glitch/features/reblogs');
-}
-
-export function Favourites () {
- return import(/* webpackChunkName: "themes/glitch/async/favourites" */'themes/glitch/features/favourites');
-}
-
-export function FollowRequests () {
- return import(/* webpackChunkName: "themes/glitch/async/follow_requests" */'themes/glitch/features/follow_requests');
-}
-
-export function GenericNotFound () {
- return import(/* webpackChunkName: "themes/glitch/async/generic_not_found" */'themes/glitch/features/generic_not_found');
-}
-
-export function FavouritedStatuses () {
- return import(/* webpackChunkName: "themes/glitch/async/favourited_statuses" */'themes/glitch/features/favourited_statuses');
-}
-
-export function Blocks () {
- return import(/* webpackChunkName: "themes/glitch/async/blocks" */'themes/glitch/features/blocks');
-}
-
-export function Mutes () {
- return import(/* webpackChunkName: "themes/glitch/async/mutes" */'themes/glitch/features/mutes');
-}
-
-export function OnboardingModal () {
- return import(/* webpackChunkName: "themes/glitch/async/onboarding_modal" */'themes/glitch/features/ui/components/onboarding_modal');
-}
-
-export function MuteModal () {
- return import(/* webpackChunkName: "themes/glitch/async/mute_modal" */'themes/glitch/features/ui/components/mute_modal');
-}
-
-export function ReportModal () {
- return import(/* webpackChunkName: "themes/glitch/async/report_modal" */'themes/glitch/features/ui/components/report_modal');
-}
-
-export function SettingsModal () {
- return import(/* webpackChunkName: "themes/glitch/async/settings_modal" */'themes/glitch/features/local_settings');
-}
-
-export function MediaGallery () {
- return import(/* webpackChunkName: "themes/glitch/async/media_gallery" */'themes/glitch/components/media_gallery');
-}
-
-export function Video () {
- return import(/* webpackChunkName: "themes/glitch/async/video" */'themes/glitch/features/video');
-}
-
-export function EmbedModal () {
- return import(/* webpackChunkName: "themes/glitch/async/embed_modal" */'themes/glitch/features/ui/components/embed_modal');
-}
diff --git a/app/javascript/themes/mastodon-go b/app/javascript/themes/mastodon-go
deleted file mode 160000
index 74c0293e83d..00000000000
--- a/app/javascript/themes/mastodon-go
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 74c0293e83dbb49ea4f27eea108526df6216d2a2
diff --git a/app/javascript/themes/vanilla/theme.yml b/app/javascript/themes/vanilla/theme.yml
deleted file mode 100644
index 0b262cc820d..00000000000
--- a/app/javascript/themes/vanilla/theme.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-# (REQUIRED) The location of the pack file inside `pack_directory`.
-pack: application.js
-
-# (OPTIONAL) The directory which contains the pack file.
-# Defaults to the theme directory (`app/javascript/themes/[theme]`),
-# but in the case of the vanilla Mastodon theme the pack file is
-# somewhere else.
-pack_directory: app/javascript/packs
-
-# (OPTIONAL) Additional javascript resources to preload, for use with
-# lazy-loaded components. It is **STRONGLY RECOMMENDED** that you
-# derive these pathnames from `themes/[your-theme]` to ensure that
-# they stay unique. (Of course, vanilla doesn't do this ^^;;)
-preload:
-- features/getting_started
-- features/compose
-- features/home_timeline
-- features/notifications
diff --git a/app/lib/themes.rb b/app/lib/themes.rb
index f7ec22fd2b8..863326e2d55 100644
--- a/app/lib/themes.rb
+++ b/app/lib/themes.rb
@@ -7,22 +7,59 @@ class Themes
include Singleton
def initialize
+
+ core = YAML.load_file(Rails.root.join('app', 'javascript', 'core', 'theme.yml'))
+ core['pack'] = Hash.new unless core['pack']
+
result = Hash.new
- Dir.glob(Rails.root.join('app', 'javascript', 'themes', '*', 'theme.yml')) do |path|
+ Dir.glob(Rails.root.join('app', 'javascript', 'flavours', '*', 'theme.yml')) do |path|
data = YAML.load_file(path)
name = File.basename(File.dirname(path))
if data['pack']
+ data['name'] = name
+ data['skin'] = { 'default' => [] }
result[name] = data
end
end
+
+ Dir.glob(Rails.root.join('app', 'javascript', 'skins', '*', '*')) do |path|
+ ext = File.extname(path)
+ skin = File.basename(path)
+ name = File.basename(File.dirname(path))
+ if result[name]
+ if File.directory?(path)
+ pack = []
+ Dir.glob(File.join(path, '*.{css,scss}')) do |sheet|
+ pack.push(File.basename(sheet, File.extname(sheet)))
+ end
+ elsif ext.match(/^\.s?css$/i)
+ skin = File.basename(path, ext)
+ pack = ['common']
+ end
+ if skin != 'default'
+ result[name]['skin'][skin] = pack
+ end
+ end
+ end
+
+ @core = core
@conf = result
+
end
- def get(name)
+ def core
+ @core
+ end
+
+ def flavour(name)
@conf[name]
end
- def names
+ def flavours
@conf.keys
end
+
+ def skins_for(name)
+ @conf[name]['skin'].keys
+ end
end
diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb
index d86959c0bb1..8af384a2d24 100644
--- a/app/lib/user_settings_decorator.rb
+++ b/app/lib/user_settings_decorator.rb
@@ -26,7 +26,8 @@ class UserSettingsDecorator
user.settings['reduce_motion'] = reduce_motion_preference if change?('setting_reduce_motion')
user.settings['system_font_ui'] = system_font_ui_preference if change?('setting_system_font_ui')
user.settings['noindex'] = noindex_preference if change?('setting_noindex')
- user.settings['theme'] = theme_preference if change?('setting_theme')
+ user.settings['flavour'] = flavour_preference if change?('setting_flavour')
+ user.settings['skin'] = skin_preference if change?('setting_skin')
end
def merged_notification_emails
@@ -73,10 +74,14 @@ class UserSettingsDecorator
boolean_cast_setting 'setting_noindex'
end
- def theme_preference
- settings['setting_theme']
+ def flavour_preference
+ settings['setting_flavour']
end
-
+
+ def skin_preference
+ settings['setting_skin']
+ end
+
def boolean_cast_setting(key)
settings[key] == '1'
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 578622fdf85..29bdcbd6713 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -76,7 +76,7 @@ class User < ApplicationRecord
has_many :session_activations, dependent: :destroy
delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal,
- :reduce_motion, :system_font_ui, :noindex, :theme,
+ :reduce_motion, :system_font_ui, :noindex, :flavour, :skin,
to: :settings, prefix: :setting, allow_nil: false
attr_accessor :invite_code
diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml
index 7ffa5ecc35d..d92362bd767 100644
--- a/app/views/about/more.html.haml
+++ b/app/views/about/more.html.haml
@@ -2,7 +2,6 @@
= site_hostname
- content_for :header_tags do
- = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
= render partial: 'shared/og'
.landing-page
diff --git a/app/views/about/show.html.haml b/app/views/about/show.html.haml
index 385b0b1dc37..4f5b53470a2 100644
--- a/app/views/about/show.html.haml
+++ b/app/views/about/show.html.haml
@@ -3,7 +3,6 @@
- content_for :header_tags do
%script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)
- = javascript_pack_tag 'about', integrity: true, crossorigin: 'anonymous'
= render partial: 'shared/og'
.landing-page
diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml
index 5747cc27408..7dd962bf23b 100644
--- a/app/views/admin/reports/show.html.haml
+++ b/app/views/admin/reports/show.html.haml
@@ -1,6 +1,3 @@
-- content_for :header_tags do
- = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'
-
- content_for :page_title do
= t('admin.reports.report', id: @report.id)
diff --git a/app/views/admin/statuses/index.html.haml b/app/views/admin/statuses/index.html.haml
index fe25815274a..9747a92cf03 100644
--- a/app/views/admin/statuses/index.html.haml
+++ b/app/views/admin/statuses/index.html.haml
@@ -1,6 +1,3 @@
-- content_for :header_tags do
- = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'
-
- content_for :page_title do
= t('admin.statuses.title')
diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml
index 63b3a0c26b3..e8a81656cc3 100644
--- a/app/views/home/index.html.haml
+++ b/app/views/home/index.html.haml
@@ -1,13 +1,7 @@
- content_for :header_tags do
- - if theme_data['preload']
- - theme_data['preload'].each do |link|
- %link{ href: asset_pack_path("#{link}.js"), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/
%meta{name: 'applicationServerKey', content: Rails.configuration.x.vapid_public_key}
%script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)
- = javascript_pack_tag "themes/#{current_theme}", integrity: true, crossorigin: 'anonymous'
- = stylesheet_pack_tag "themes/#{current_theme}", integrity: true, media: 'all'
-
.app-holder#mastodon{ data: { props: Oj.dump(default_props) } }
%noscript
= image_tag asset_pack_path('logo.svg'), alt: 'Mastodon'
diff --git a/app/views/layouts/_theme.html.haml b/app/views/layouts/_theme.html.haml
new file mode 100644
index 00000000000..066d9de42fe
--- /dev/null
+++ b/app/views/layouts/_theme.html.haml
@@ -0,0 +1,13 @@
+- if theme
+ - if theme[:pack] != 'common' && theme[:common]
+ = render partial: 'layouts/theme', object: theme[:common]
+ - if theme[:pack]
+ = javascript_pack_tag theme[:flavour] ? "flavours/#{theme[:flavour]}/#{theme[:pack]}" : "core/#{theme[:pack]}", integrity: true, crossorigin: 'anonymous'
+ - if theme[:skin]
+ - if !theme[:flavour] || theme[:skin] == 'default'
+ = stylesheet_pack_tag theme[:flavour] ? "flavours/#{theme[:flavour]}/#{theme[:pack]}" : "core/#{theme[:pack]}", integrity: true, media: 'all'
+ - else
+ = stylesheet_pack_tag "skins/#{theme[:flavour]}/#{theme[:skin]}/#{theme[:pack]}"
+ - if theme[:preload]
+ - theme[:preload].each do |link|
+ %link{ href: asset_pack_path("#{link}.js"), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index c98d85f7bfe..66382db5000 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -1,6 +1,3 @@
-- content_for :header_tags do
- = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
-
- content_for :content do
.admin-wrapper
.sidebar-wrapper
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 24b74c787c0..99ae7d90d65 100755
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -18,16 +18,16 @@
= ' - '
= title
- = stylesheet_pack_tag 'common', media: 'all'
- = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'
+ = javascript_pack_tag "locales", integrity: true, crossorigin: 'anonymous'
= javascript_pack_tag "locale_#{I18n.locale}", integrity: true, crossorigin: 'anonymous'
= csrf_meta_tags
- - if controller_name != 'home'
- = stylesheet_pack_tag 'application', integrity: true, media: 'all'
-
= yield :header_tags
+ -# These must come after :header_tags to ensure our initial state has been defined.
+ = render partial: 'layouts/theme', object: @core
+ = render partial: 'layouts/theme', object: @theme
+
- body_classes ||= @body_classes || ''
- body_classes += ' system-font' if current_account&.user&.setting_system_font_ui
diff --git a/app/views/layouts/auth.html.haml b/app/views/layouts/auth.html.haml
index d8ac733f913..f4812ac6a3d 100644
--- a/app/views/layouts/auth.html.haml
+++ b/app/views/layouts/auth.html.haml
@@ -1,6 +1,3 @@
-- content_for :header_tags do
- = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
-
- content_for :content do
.container
.logo-container
diff --git a/app/views/layouts/embedded.html.haml b/app/views/layouts/embedded.html.haml
index 5fc60be170b..93567051466 100644
--- a/app/views/layouts/embedded.html.haml
+++ b/app/views/layouts/embedded.html.haml
@@ -4,10 +4,8 @@
%meta{ charset: 'utf-8' }/
%meta{ name: 'robots', content: 'noindex' }/
- = stylesheet_pack_tag 'common', media: 'all'
- = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'
- = stylesheet_pack_tag 'application', integrity: true, media: 'all'
+ = javascript_pack_tag "locales", integrity: true, crossorigin: 'anonymous'
= javascript_pack_tag "locale_#{I18n.locale}", integrity: true, crossorigin: 'anonymous'
- = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
- %body.embed
+ = render partial: 'layouts/theme', object: @core
+ = render partial: 'layouts/theme', object: @theme
= yield
diff --git a/app/views/layouts/error.html.haml b/app/views/layouts/error.html.haml
index d0eae44346c..9904b8fdd79 100644
--- a/app/views/layouts/error.html.haml
+++ b/app/views/layouts/error.html.haml
@@ -5,8 +5,8 @@
%meta{ charset: 'utf-8' }/
%title= safe_join([yield(:page_title), Setting.default_settings['site_title']], ' - ')
%meta{ content: 'width=device-width,initial-scale=1', name: 'viewport' }/
- = stylesheet_pack_tag 'common', media: 'all'
- = stylesheet_pack_tag 'application', integrity: true, media: 'all'
+ = render partial: 'layouts/theme', object: @core
+ = render partial: 'layouts/theme', object: @theme
%body.error
.dialog
%img{ alt: Setting.default_settings['site_title'], src: '/oops.gif' }/
diff --git a/app/views/layouts/modal.html.haml b/app/views/layouts/modal.html.haml
index a819e098d6c..d3519f032fa 100644
--- a/app/views/layouts/modal.html.haml
+++ b/app/views/layouts/modal.html.haml
@@ -1,6 +1,3 @@
-- content_for :header_tags do
- = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
-
- content_for :content do
- if user_signed_in?
.account-header
diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml
index 83e92b938f3..b3795eaadd0 100644
--- a/app/views/layouts/public.html.haml
+++ b/app/views/layouts/public.html.haml
@@ -1,6 +1,3 @@
-- content_for :header_tags do
- = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
-
- content_for :content do
.container= yield
.footer
diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml
index 69e26a7be2c..9564c039919 100644
--- a/app/views/settings/preferences/show.html.haml
+++ b/app/views/settings/preferences/show.html.haml
@@ -26,8 +26,9 @@
%h4= t 'preferences.web'
.fields-group
- - if Themes.instance.names.size > 1
- = f.input :setting_theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, include_blank: false
+ - if Themes.instance.flavours.size > 1
+ = f.input :setting_flavour, collection: Themes.instance.flavours, label_method: lambda { |flavour| I18n.t("themes.#{flavour}", default: flavour) }, wrapper: :with_label, include_blank: false
+ = f.input :setting_skin, collection: Themes.instance.skins_for(current_flavour), label_method: lambda { |skin| I18n.t("themes.#{current_flavour}.skins.#{skin}", default: skin) }, wrapper: :with_label, include_blank: false
= f.input :setting_unfollow_modal, as: :boolean, wrapper: :with_label
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
diff --git a/app/views/shares/show.html.haml b/app/views/shares/show.html.haml
index 44b6f145f68..4c0390c4213 100644
--- a/app/views/shares/show.html.haml
+++ b/app/views/shares/show.html.haml
@@ -1,5 +1,4 @@
- content_for :header_tags do
%script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)
- = javascript_pack_tag 'share', integrity: true, crossorigin: 'anonymous'
#mastodon-compose{ data: { props: Oj.dump(default_props) } }
diff --git a/app/views/tags/show.html.haml b/app/views/tags/show.html.haml
index ea8b0faa333..e05fe1c3952 100644
--- a/app/views/tags/show.html.haml
+++ b/app/views/tags/show.html.haml
@@ -3,7 +3,6 @@
- content_for :header_tags do
%script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)
- = javascript_pack_tag 'about', integrity: true, crossorigin: 'anonymous'
= render 'og'
.landing-page.tag-page
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index ff1a40ccd0f..756f6b11906 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -13,8 +13,9 @@ en:
note:
one: 1 character left
other: %{count} characters left
+ setting_flavour: Affects how Mastodon looks when you're logged in from any device
setting_noindex: Affects your public profile and status pages
- setting_theme: Affects how Mastodon looks when you're logged in from any device.
+ setting_skin: Reskins the selected Mastodon flavour
imports:
data: CSV file exported from another Mastodon instance
sessions:
@@ -45,10 +46,11 @@ en:
setting_default_privacy: Post privacy
setting_default_sensitive: Always mark media as sensitive
setting_delete_modal: Show confirmation dialog before deleting a toot
+ setting_flavour: Flavour
setting_noindex: Opt-out of search engine indexing
setting_reduce_motion: Reduce motion in animations
+ setting_skin: Skin
setting_system_font_ui: Use system's default font
- setting_theme: Site theme
setting_unfollow_modal: Show confirmation dialog before unfollowing someone
severity: Severity
type: Import type
diff --git a/config/settings.yml b/config/settings.yml
index 01478972c02..5aad45da225 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -27,7 +27,8 @@ defaults: &defaults
reduce_motion: false
system_font_ui: false
noindex: false
- theme: 'glitch'
+ flavour: 'glitch'
+ skin: 'default'
notification_emails:
follow: false
reblog: false
diff --git a/config/webpack/configuration.js b/config/webpack/configuration.js
index 74f75d89b38..59d46c78d4e 100644
--- a/config/webpack/configuration.js
+++ b/config/webpack/configuration.js
@@ -1,25 +1,57 @@
// Common configuration for webpacker loaded from config/webpacker.yml
-const { basename, dirname, join, resolve } = require('path');
+const { basename, dirname, extname, join, resolve } = require('path');
const { env } = require('process');
const { safeLoad } = require('js-yaml');
-const { readFileSync } = require('fs');
+const { lstatSync, readFileSync } = require('fs');
const glob = require('glob');
const configPath = resolve('config', 'webpacker.yml');
const loadersDir = join(__dirname, 'loaders');
const settings = safeLoad(readFileSync(configPath), 'utf8')[env.NODE_ENV];
-const themeFiles = glob.sync('app/javascript/themes/*/theme.yml');
-const themes = {};
+const flavourFiles = glob.sync('app/javascript/flavours/*/theme.yml');
+const skinFiles = glob.sync('app/javascript/skins/*/*');
+const flavours = {};
-for (let i = 0; i < themeFiles.length; i++) {
- const themeFile = themeFiles[i];
- const data = safeLoad(readFileSync(themeFile), 'utf8');
+const core = function () {
+ const coreFile = resolve('app', 'javascript', 'core', 'theme.yml');
+ const data = safeLoad(readFileSync(coreFile), 'utf8');
if (!data.pack_directory) {
- data.pack_directory = dirname(themeFile);
+ data.pack_directory = dirname(coreFile);
}
- if (data.pack) {
- themes[basename(dirname(themeFile))] = data;
+ return data.pack ? data : {};
+}();
+
+for (let i = 0; i < flavourFiles.length; i++) {
+ const flavourFile = flavourFiles[i];
+ const data = safeLoad(readFileSync(flavourFile), 'utf8');
+ data.name = basename(dirname(flavourFile));
+ data.skin = {};
+ if (!data.pack_directory) {
+ data.pack_directory = dirname(flavourFile);
+ }
+ if (data.pack && typeof data.pack === 'object') {
+ flavours[data.name] = data;
+ }
+}
+
+for (let i = 0; i < skinFiles.length; i++) {
+ const skinFile = skinFiles[i];
+ let skin = basename(skinFile);
+ const name = basename(dirname(skinFile));
+ if (!flavours[name]) {
+ continue;
+ }
+ const data = flavours[name].skin;
+ if (lstatSync(skinFile).isDirectory()) {
+ data[skin] = {};
+ const skinPacks = glob.sync(skinFile, '*.{css,scss}');
+ for (let j = 0; j < skinPacks.length; j++) {
+ const pack = skinPacks[i];
+ data[skin][basename(pack, extname(pack))] = pack;
+ }
+ } else if ((skin = skin.match(/^(.*)\.s?css$/i))) {
+ data[skin[1]] = { common: skinFile };
}
}
@@ -43,7 +75,8 @@ const output = {
module.exports = {
settings,
- themes,
+ core,
+ flavours,
env,
loadersDir,
output,
diff --git a/config/webpack/generateLocalePacks.js b/config/webpack/generateLocalePacks.js
index cd3bed50c0e..a943589f74c 100644
--- a/config/webpack/generateLocalePacks.js
+++ b/config/webpack/generateLocalePacks.js
@@ -57,7 +57,7 @@ Object.keys(glitchMessages).forEach(function (key) {
//
import messages from '../../app/javascript/mastodon/locales/${locale}.json';
import localeData from ${JSON.stringify(localeDataPath)};
-import { setLocale } from '../../app/javascript/mastodon/locales';
+import { setLocale } from 'locales';
${glitchInject}
setLocale({messages: mergedMessages, localeData: localeData});
`;
diff --git a/config/webpack/shared.js b/config/webpack/shared.js
index 5d176db4eb3..e4b057ffbd7 100644
--- a/config/webpack/shared.js
+++ b/config/webpack/shared.js
@@ -1,38 +1,60 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
const webpack = require('webpack');
-const { basename, dirname, join, relative, resolve } = require('path');
+const { basename, join, resolve } = require('path');
const { sync } = require('glob');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const extname = require('path-complete-extname');
-const { env, settings, themes, output, loadersDir } = require('./configuration.js');
+const { env, settings, core, flavours, output, loadersDir } = require('./configuration.js');
const localePackPaths = require('./generateLocalePacks');
-const extensionGlob = `**/*{${settings.extensions.join(',')}}*`;
-const entryPath = join(settings.source_path, settings.source_entry_path);
-const packPaths = sync(join(entryPath, extensionGlob));
+function reducePacks (data, into = {}) {
+ if (!data.pack) {
+ return into;
+ }
+ Object.keys(data.pack).reduce((map, entry) => {
+ const pack = data.pack[entry];
+ if (!pack) {
+ return map;
+ }
+ const packFile = typeof pack === 'string' ? pack : pack.filename;
+ if (packFile) {
+ map[data.name ? `flavours/${data.name}/${entry}` : `core/${entry}`] = resolve(data.pack_directory, packFile);
+ }
+ return map;
+ }, into);
+ if (data.name) {
+ Object.keys(data.skin).reduce((map, entry) => {
+ const skin = data.skin[entry];
+ const skinName = entry;
+ if (!skin) {
+ return map;
+ }
+ Object.keys(skin).reduce((map, entry) => {
+ const packFile = skin[entry];
+ if (!packFile) {
+ return map;
+ }
+ map[`skins/${data.name}/${skinName}/${entry}`] = resolve(packFile);
+ return map;
+ }, into);
+ return map;
+ }, into);
+ }
+ return into;
+}
module.exports = {
entry: Object.assign(
- packPaths.reduce((map, entry) => {
- const localMap = map;
- const namespace = relative(join(entryPath), dirname(entry));
- localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry);
- return localMap;
- }, {}),
+ { locales: resolve('app', 'javascript', 'locales') },
localePackPaths.reduce((map, entry) => {
const localMap = map;
localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry);
return localMap;
}, {}),
- Object.keys(themes).reduce(
- (themePaths, name) => {
- const themeData = themes[name];
- themePaths[`themes/${name}`] = resolve(themeData.pack_directory, themeData.pack);
- return themePaths;
- }, {}
- )
+ reducePacks(core),
+ Object.keys(flavours).reduce((map, entry) => reducePacks(flavours[entry], map), {})
),
output: {
@@ -64,7 +86,7 @@ module.exports = {
writeToFileEmit: true,
}),
new webpack.optimize.CommonsChunkPlugin({
- name: 'common',
+ name: 'locales',
minChunks: Infinity, // It doesn't make sense to use common chunks with multiple frontend support.
}),
],
diff --git a/config/webpacker.yml b/config/webpacker.yml
index 8d8470651ac..50d95813a54 100644
--- a/config/webpacker.yml
+++ b/config/webpacker.yml
@@ -2,7 +2,6 @@
default: &default
source_path: app/javascript
- source_entry_path: packs
public_output_path: packs
cache_path: tmp/cache/webpacker
@@ -13,17 +12,6 @@ default: &default
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
- extensions:
- - .js
- - .sass
- - .scss
- - .css
- - .png
- - .svg
- - .gif
- - .jpeg
- - .jpg
-
development:
<<: *default
compile: true