Finalized theme loading and stuff
This commit is contained in:
		
							parent
							
								
									321fa41930
								
							
						
					
					
						commit
						bdbbd06dad
					
				| @ -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 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -4,8 +4,13 @@ module Admin | ||||
|   class BaseController < ApplicationController | ||||
|     include Authorization | ||||
| 
 | ||||
|     before_action :require_staff! | ||||
| 
 | ||||
|     layout 'admin' | ||||
| 
 | ||||
|     before_action :require_staff! | ||||
|     before_action :set_pack | ||||
| 
 | ||||
|     def set_pack | ||||
|       use_pack 'admin' | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| @ -12,8 +12,6 @@ class ApplicationController < ActionController::Base | ||||
| 
 | ||||
|   helper_method :current_account | ||||
|   helper_method :current_session | ||||
|   helper_method :current_theme | ||||
|   helper_method :theme_data | ||||
|   helper_method :single_user_mode? | ||||
| 
 | ||||
|   rescue_from ActionController::RoutingError, with: :not_found | ||||
| @ -54,6 +52,69 @@ class ApplicationController < ActionController::Base | ||||
|     new_user_session_path | ||||
|   end | ||||
| 
 | ||||
|   def pack(data, pack_name) | ||||
|     return nil unless pack?(data, pack_name) | ||||
|     pack_data = { | ||||
|       common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.get(current_theme) : Themes.instance.core, 'common'), | ||||
|       name: data['name'], | ||||
|       pack: pack_name, | ||||
|       preload: nil, | ||||
|       stylesheet: false | ||||
|     } | ||||
|     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 | ||||
|       pack_data[:stylesheet] = true if data['pack'][pack_name]['stylesheet'] | ||||
|     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) | ||||
|     { | ||||
|       common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.get(current_theme) : Themes.instance.core, 'common'), | ||||
|       name: data['name'], | ||||
|       pack: nil, | ||||
|       preload: nil, | ||||
|       stylesheet: false | ||||
|     } | ||||
|   end | ||||
| 
 | ||||
|   def resolve_pack(data, pack_name) | ||||
|     result = pack(data, pack_name) | ||||
|     unless result | ||||
|       if data['name'] && data.key?('fallback') | ||||
|         if data['fallback'].nil? | ||||
|           return nil_pack(data, pack_name) | ||||
|         elsif data['fallback'].is_a?(String) && Themes.instance.get(data['fallback']) | ||||
|           return resolve_pack(Themes.instance.get(data['fallback']), pack_name) | ||||
|         elsif data['fallback'].is_a?(Array) | ||||
|           data['fallback'].each do |fallback| | ||||
|             return resolve_pack(Themes.instance.get(fallback), pack_name) if Themes.instance.get(fallback) | ||||
|           end | ||||
|         end | ||||
|         return nil_pack(data, pack_name) | ||||
|       end | ||||
|       return data.key?('name') && data['name'] != default_theme ? resolve_pack(Themes.instance.get(default_theme), pack_name) : nil_pack(data, pack_name) | ||||
|     end | ||||
|     result | ||||
|   end | ||||
| 
 | ||||
|   def use_pack(pack_name) | ||||
|     @core = resolve_pack(Themes.instance.core, pack_name) | ||||
|     @theme = resolve_pack(Themes.instance.get(current_theme), pack_name) | ||||
|   end | ||||
| 
 | ||||
|   protected | ||||
| 
 | ||||
|   def forbidden | ||||
| @ -84,13 +145,13 @@ 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 default_theme | ||||
|     Setting.default_settings['theme'] | ||||
|   end | ||||
| 
 | ||||
|   def theme_data | ||||
|     Themes.instance.get(current_theme) | ||||
|   def current_theme | ||||
|     return default_theme unless Themes.instance.names.include? current_user&.setting_theme | ||||
|     current_user.setting_theme | ||||
|   end | ||||
| 
 | ||||
|   def cache_collection(raw, klass) | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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_path | ||||
|   before_action :set_sessions, only: [:edit, :update] | ||||
|   before_action :set_instance_presenter, only: [:new, :create, :update] | ||||
| 
 | ||||
| @ -40,6 +41,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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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] | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										12
									
								
								app/controllers/settings/base_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/controllers/settings/base_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| @ -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! | ||||
| 
 | ||||
|   def show | ||||
|     @confirmation = Form::DeleteConfirmation.new | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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] | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| #  Intentionally does not inherit from BaseController | ||||
| class Settings::SessionsController < ApplicationController | ||||
|   before_action :set_session, only: :destroy | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| //  This file will be loaded on about pages, regardless of theme.
 | ||||
| @ -13,7 +13,7 @@ window.addEventListener('message', e => { | ||||
|       id: data.id, | ||||
|       height: document.getElementsByTagName('html')[0].scrollHeight, | ||||
|     }, '*'); | ||||
|   }); | ||||
|   }; | ||||
| 
 | ||||
|   if (['interactive', 'complete'].includes(document.readyState)) { | ||||
|     setEmbedHeight(); | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| //  This file will be loaded on home pages, regardless of theme.
 | ||||
| @ -1 +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; | ||||
| }); | ||||
|  | ||||
| @ -1,65 +1,37 @@ | ||||
| //  This file will be loaded on settings pages, regardless of theme.
 | ||||
| 
 | ||||
| function main() { | ||||
|   const { length } = require('stringz'); | ||||
|   const { delegate } = require('rails-ujs'); | ||||
| const { length } = require('stringz'); | ||||
| 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, '.account_display_name', 'input', ({ target }) => { | ||||
|   const nameCounter = document.querySelector('.name-counter'); | ||||
| 
 | ||||
|   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 => { | ||||
|   console.error(error); | ||||
|   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})`; | ||||
| }); | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| //  This file will be loaded on share pages, regardless of theme.
 | ||||
							
								
								
									
										14
									
								
								app/javascript/core/theme.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/javascript/core/theme.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #  These packs will be loaded on every appropriate page, regardless of | ||||
| #  theme. | ||||
| pack: | ||||
|   about: | ||||
|   admin: admin.js | ||||
|   auth: | ||||
|   common: common.js | ||||
|   embed: embed.js | ||||
|   error: | ||||
|   home: | ||||
|   modal: | ||||
|   public: public.js | ||||
|   settings: settings.js | ||||
|   share: | ||||
							
								
								
									
										9
									
								
								app/javascript/locales/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/javascript/locales/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| let theLocale; | ||||
| 
 | ||||
| export function setLocale(locale) { | ||||
|   theLocale = locale; | ||||
| } | ||||
| 
 | ||||
| export function getLocale() { | ||||
|   return theLocale; | ||||
| } | ||||
| @ -1,9 +1 @@ | ||||
| let theLocale; | ||||
| 
 | ||||
| export function setLocale(locale) { | ||||
|   theLocale = locale; | ||||
| } | ||||
| 
 | ||||
| export function getLocale() { | ||||
|   return theLocale; | ||||
| } | ||||
| export * from 'locales'; | ||||
|  | ||||
							
								
								
									
										22
									
								
								app/javascript/packs/about.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/javascript/packs/about.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| import loadPolyfills from '../mastodon/load_polyfills'; | ||||
| 
 | ||||
| function loaded() { | ||||
|   const TimelineContainer = require('../mastodon/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(<TimelineContainer {...props} />, mountNode); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function main() { | ||||
|   const ready = require('../mastodon/ready').default; | ||||
|   ready(loaded); | ||||
| } | ||||
| 
 | ||||
| loadPolyfills().then(main).catch(error => { | ||||
|   console.error(error); | ||||
| }); | ||||
| @ -1,15 +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
 | ||||
| import 'font-awesome/css/font-awesome.css'; | ||||
| import '../styles/application.scss'; | ||||
| 
 | ||||
| require.context('../images/', true); | ||||
| 
 | ||||
| loadPolyfills().then(() => { | ||||
|   require('../mastodon/main').default(); | ||||
| }).catch(e => { | ||||
|  | ||||
							
								
								
									
										3
									
								
								app/javascript/packs/common.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/javascript/packs/common.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| import 'font-awesome/css/font-awesome.css'; | ||||
| import 'styles/application.scss' | ||||
| require.context('../images/', true); | ||||
							
								
								
									
										75
									
								
								app/javascript/packs/public.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								app/javascript/packs/public.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| import loadPolyfills from '../mastodon/load_polyfills'; | ||||
| import ready from '../mastodon/ready'; | ||||
| 
 | ||||
| function main() { | ||||
|   const IntlRelativeFormat = require('intl-relativeformat').default; | ||||
|   const emojify = require('../mastodon/features/emoji/emoji').default; | ||||
|   const { getLocale } = require('../mastodon/locales'); | ||||
|   const { localeData } = getLocale(); | ||||
|   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'); | ||||
| 
 | ||||
|   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(<VideoContainer locale={locale} {...props} />, content); | ||||
|     }); | ||||
| 
 | ||||
|     [].forEach.call(document.querySelectorAll('[data-component="MediaGallery"]'), (content) => { | ||||
|       const props = JSON.parse(content.getAttribute('data-props')); | ||||
|       ReactDOM.render(<MediaGalleryContainer locale={locale} {...props} />, content); | ||||
|     }); | ||||
| 
 | ||||
|     [].forEach.call(document.querySelectorAll('[data-component="Card"]'), (content) => { | ||||
|       const props = JSON.parse(content.getAttribute('data-props')); | ||||
|       ReactDOM.render(<CardContainer locale={locale} {...props} />, content); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| loadPolyfills().then(main).catch(error => { | ||||
|   console.error(error); | ||||
| }); | ||||
							
								
								
									
										22
									
								
								app/javascript/packs/share.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/javascript/packs/share.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| import loadPolyfills from '../mastodon/load_polyfills'; | ||||
| 
 | ||||
| function loaded() { | ||||
|   const ComposeContainer = require('../mastodon/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(<ComposeContainer {...props} />, mountNode); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function main() { | ||||
|   const ready = require('../mastodon/ready').default; | ||||
|   ready(loaded); | ||||
| } | ||||
| 
 | ||||
| loadPolyfills().then(main).catch(error => { | ||||
|   console.error(error); | ||||
| }); | ||||
| @ -1,5 +0,0 @@ | ||||
| // This makes our fonts available everywhere. | ||||
| 
 | ||||
| @import 'fonts/roboto'; | ||||
| @import 'fonts/roboto-mono'; | ||||
| @import 'fonts/montserrat'; | ||||
| @ -1,3 +1,8 @@ | ||||
| //  win95 theme from cybrespace. | ||||
| 
 | ||||
| //  Modified to inherit glitch styles (themes/glitch/styles/index.scss) | ||||
| //  instead of vanilla ones (./application.scss) | ||||
| 
 | ||||
| $win95-bg: #bfbfbf; | ||||
| $win95-dark-grey: #404040; | ||||
| $win95-mid-grey: #808080; | ||||
| @ -71,7 +76,7 @@ $ui-highlight-color: $win95-window-header; | ||||
|   src: url('../fonts/premillenium/MSSansSerif.ttf') format('truetype'); | ||||
| } | ||||
| 
 | ||||
| @import 'application'; | ||||
| @import '../themes/glitch/styles/index';  //  Imports glitch themes | ||||
| 
 | ||||
| /* borrowed from cybrespace style: wider columns and full column width images */ | ||||
| 
 | ||||
|  | ||||
| @ -9,7 +9,7 @@ import UI from 'themes/glitch/features/ui'; | ||||
| import { hydrateStore } from 'themes/glitch/actions/store'; | ||||
| import { connectUserStream } from 'themes/glitch/actions/streaming'; | ||||
| import { IntlProvider, addLocaleData } from 'react-intl'; | ||||
| import { getLocale } from 'mastodon/locales'; | ||||
| import { getLocale } from 'locales'; | ||||
| import initialState from 'themes/glitch/util/initial_state'; | ||||
| 
 | ||||
| const { localeData, messages } = getLocale(); | ||||
|  | ||||
| @ -1,3 +1,3 @@ | ||||
| import 'font-awesome/css/font-awesome.css'; | ||||
| require.context('../../images/', true); | ||||
| import './styles/index.scss'; | ||||
| require.context('images/', true); | ||||
| import 'themes/glitch/styles/index.scss'; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import loadPolyfills from './util/load_polyfills'; | ||||
| import loadPolyfills from 'themes/glitch/util/load_polyfills'; | ||||
| 
 | ||||
| loadPolyfills().then(() => { | ||||
|   require('./util/main').default(); | ||||
|   require('themes/glitch/util/main').default(); | ||||
| }).catch(e => { | ||||
|   console.error(e); | ||||
| }); | ||||
|  | ||||
| @ -2,32 +2,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, | ||||
|     }, '*'); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| 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('themes/glitch/util/emoji').default; | ||||
|   const { getLocale } = require('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('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 React = require('react'); | ||||
|   const ReactDOM = require('react-dom'); | ||||
| 
 | ||||
| @ -87,61 +69,6 @@ function main() { | ||||
|       ReactDOM.render(<CardContainer locale={locale} {...props} />, 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 => { | ||||
|  | ||||
| @ -1,25 +1,34 @@ | ||||
| #  (REQUIRED) The location of the pack files. | ||||
| pack: | ||||
|   about: packs/about.js | ||||
|   admin: null | ||||
|   common: packs/common.js | ||||
|   embed: null | ||||
|   home: packs/home.js | ||||
|   admin: | ||||
|   auth: | ||||
|   common: | ||||
|     filename: packs/common.js | ||||
|     stylesheet: true | ||||
|   embed: packs/public.js | ||||
|   error: | ||||
|   home: | ||||
|     filename: packs/home.js | ||||
|     preload: | ||||
|     - themes/glitch/async/getting_started | ||||
|     - themes/glitch/async/compose | ||||
|     - themes/glitch/async/home_timeline | ||||
|     - themes/glitch/async/notifications | ||||
|     stylesheet: true | ||||
|   modal: | ||||
|   public: packs/public.js | ||||
|   settings: null | ||||
|   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) 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. | ||||
| preload: | ||||
| - themes/glitch/async/getting_started | ||||
| - themes/glitch/async/compose | ||||
| - themes/glitch/async/home_timeline | ||||
| - themes/glitch/async/notifications | ||||
| #      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: | ||||
|  | ||||
| @ -1,12 +1,23 @@ | ||||
| #  (REQUIRED) The location of the pack files inside `pack_directory`. | ||||
| pack: | ||||
|   about: about.js | ||||
|   admin: null | ||||
|   common: common.js | ||||
|   embed: null | ||||
|   home: application.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: null | ||||
|   settings: | ||||
|   share: share.js | ||||
| 
 | ||||
| #  (OPTIONAL) The directory which contains the pack files. | ||||
| @ -15,12 +26,8 @@ pack: | ||||
| #  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 | ||||
| #  (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: | ||||
|  | ||||
							
								
								
									
										10
									
								
								app/javascript/themes/win95/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/javascript/themes/win95/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| //  These lines are the same as in glitch:
 | ||||
| import 'font-awesome/css/font-awesome.css'; | ||||
| require.context('../../images/', true); | ||||
| 
 | ||||
| //  …But we want to use our own styles instead.
 | ||||
| import 'styles/win95.scss'; | ||||
| 
 | ||||
| //  Be sure to make this style file import from
 | ||||
| //  `themes/glitch/styles/index.scss` (the glitch styling), and not
 | ||||
| //  `application.scss` (which are the vanilla styles).
 | ||||
							
								
								
									
										23
									
								
								app/javascript/themes/win95/theme.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/javascript/themes/win95/theme.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| #  win95 theme. | ||||
| 
 | ||||
| #  Ported over from `cybrespace:mastodon/theme_win95`. | ||||
| #  <https://github.com/cybrespace/mastodon/tree/theme_win95> | ||||
| 
 | ||||
| #  You can use this theme file as inspiration for porting over | ||||
| #  a preëxisting Mastodon theme. | ||||
| 
 | ||||
| #  We only modify the `common` pack, which contains our styling. | ||||
| pack: | ||||
|   common: | ||||
|     filename: index.js | ||||
|     stylesheet: true | ||||
|   #  All unspecified packs will inherit from glitch. | ||||
| 
 | ||||
| #  By default, the glitch preloads will also be used here. You can | ||||
| #  disable them by setting `preload` to `null`. | ||||
| 
 | ||||
| #      preload: | ||||
| 
 | ||||
| #  The `fallback` parameter tells us to use glitch files for everything | ||||
| #  we haven't specified. | ||||
| fallback: glitch | ||||
| @ -7,15 +7,27 @@ 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| | ||||
|       data = YAML.load_file(path) | ||||
|       name = File.basename(File.dirname(path)) | ||||
|       if data['pack'] | ||||
|         data['name'] = name | ||||
|         result[name] = data | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     @core = core | ||||
|     @conf = result | ||||
| 
 | ||||
|   end | ||||
| 
 | ||||
|   def core | ||||
|     @core | ||||
|   end | ||||
| 
 | ||||
|   def get(name) | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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) | ||||
| 
 | ||||
|  | ||||
| @ -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') | ||||
| 
 | ||||
|  | ||||
| @ -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' | ||||
|  | ||||
							
								
								
									
										10
									
								
								app/views/layouts/_theme.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/views/layouts/_theme.html.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| - if theme | ||||
|   - if theme[:pack] != 'common' && theme[:common] | ||||
|     = render partial: 'layouts/theme', object: theme[:common] | ||||
|   - if theme[:pack] | ||||
|     = javascript_pack_tag theme[:name] ? "themes/#{theme[:name]}/#{theme[:pack]}" : "core/#{theme[:pack]}", integrity: true, crossorigin: 'anonymous' | ||||
|     - if theme[:stylesheet] | ||||
|       = stylesheet_pack_tag theme[:name] ? "themes/#{theme[:name]}/#{theme[:pack]}" : "core/#{theme[:pack]}", integrity: true, media: 'all' | ||||
|     - if theme[:preload] | ||||
|       - theme[:preload].each do |link| | ||||
|         %link{ href: asset_pack_path("#{link}.js"), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,3 @@ | ||||
| - content_for :header_tags do | ||||
|   = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous' | ||||
| 
 | ||||
| - content_for :content do | ||||
|   .container | ||||
|     .logo-container | ||||
|  | ||||
| @ -4,10 +4,9 @@ | ||||
|     %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 'embed', 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 | ||||
|  | ||||
| @ -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' }/ | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -1,6 +1,3 @@ | ||||
| - content_for :header_tags do | ||||
|   = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous' | ||||
| 
 | ||||
| - content_for :content do | ||||
|   .container= yield | ||||
|   .footer | ||||
|  | ||||
| @ -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) } } | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -12,14 +12,24 @@ const settings = safeLoad(readFileSync(configPath), 'utf8')[env.NODE_ENV]; | ||||
| const themeFiles = glob.sync('app/javascript/themes/*/theme.yml'); | ||||
| const themes = {}; | ||||
| 
 | ||||
| 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(coreFile); | ||||
|   } | ||||
|   return data.pack ? data : {}; | ||||
| }(); | ||||
| 
 | ||||
| for (let i = 0; i < themeFiles.length; i++) { | ||||
|   const themeFile = themeFiles[i]; | ||||
|   const data = safeLoad(readFileSync(themeFile), 'utf8'); | ||||
|   data.name = basename(dirname(themeFile)); | ||||
|   if (!data.pack_directory) { | ||||
|     data.pack_directory = dirname(themeFile); | ||||
|   } | ||||
|   if (data.pack) { | ||||
|     themes[basename(dirname(themeFile))] = data; | ||||
|     themes[data.name] = data; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @ -43,6 +53,7 @@ const output = { | ||||
| 
 | ||||
| module.exports = { | ||||
|   settings, | ||||
|   core, | ||||
|   themes, | ||||
|   env, | ||||
|   loadersDir, | ||||
|  | ||||
| @ -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}); | ||||
| `;
 | ||||
|  | ||||
| @ -6,33 +6,37 @@ 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, themes, 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 ? `themes/${data.name}/${entry}` : `core/${entry}`] = resolve(data.pack_directory, packFile); | ||||
|     } | ||||
|     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(themes).reduce((map, entry) => reducePacks(themes[entry], map), {}) | ||||
|   ), | ||||
| 
 | ||||
|   output: { | ||||
| @ -64,7 +68,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.
 | ||||
|     }), | ||||
|   ], | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user