mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2024-11-25 17:51:36 +01:00
Finalized theme loading and stuff
This commit is contained in:
parent
321fa41930
commit
bdbbd06dad
73 changed files with 573 additions and 378 deletions
|
@ -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;
|
||||
|
@ -17,7 +22,7 @@ $ui-highlight-color: $win95-window-header;
|
|||
}
|
||||
|
||||
@mixin win95-outset() {
|
||||
box-shadow: inset -1px -1px 0px #000000,
|
||||
box-shadow: inset -1px -1px 0px #000000,
|
||||
inset 1px 1px 0px #ffffff,
|
||||
inset -2px -2px 0px #808080,
|
||||
inset 2px 2px 0px #dfdfdf;
|
||||
|
@ -41,7 +46,7 @@ $ui-highlight-color: $win95-window-header;
|
|||
}
|
||||
|
||||
@mixin win95-inset() {
|
||||
box-shadow: inset 1px 1px 0px #000000,
|
||||
box-shadow: inset 1px 1px 0px #000000,
|
||||
inset -1px -1px 0px #ffffff,
|
||||
inset 2px 2px 0px #808080,
|
||||
inset -2px -2px 0px #dfdfdf;
|
||||
|
@ -51,7 +56,7 @@ $ui-highlight-color: $win95-window-header;
|
|||
|
||||
|
||||
@mixin win95-tab() {
|
||||
box-shadow: inset -1px 0px 0px #000000,
|
||||
box-shadow: inset -1px 0px 0px #000000,
|
||||
inset 1px 0px 0px #ffffff,
|
||||
inset 0px 1px 0px #ffffff,
|
||||
inset 0px 2px 0px #dfdfdf,
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -174,7 +179,7 @@ body.admin {
|
|||
font-size:0px;
|
||||
color:$win95-bg;
|
||||
|
||||
background-image: url("../images/start.png");
|
||||
background-image: url("../images/start.png");
|
||||
background-repeat:no-repeat;
|
||||
background-position:8%;
|
||||
background-clip:padding-box;
|
||||
|
@ -336,7 +341,7 @@ body.admin {
|
|||
border-radius:0px;
|
||||
background-color:white;
|
||||
@include win95-border-inset();
|
||||
|
||||
|
||||
width:12px;
|
||||
height:12px;
|
||||
}
|
||||
|
@ -515,9 +520,9 @@ body.admin {
|
|||
color:black;
|
||||
font-weight:bold;
|
||||
}
|
||||
.account__avatar,
|
||||
.account__avatar-overlay-base,
|
||||
.account__header__avatar,
|
||||
.account__avatar,
|
||||
.account__avatar-overlay-base,
|
||||
.account__header__avatar,
|
||||
.account__avatar-overlay-overlay {
|
||||
@include win95-border-slight-inset();
|
||||
clip-path:none;
|
||||
|
@ -627,7 +632,7 @@ body.admin {
|
|||
}
|
||||
|
||||
.status-card__description {
|
||||
color:black;
|
||||
color:black;
|
||||
}
|
||||
|
||||
.account__display-name strong, .status__display-name strong {
|
||||
|
@ -710,8 +715,8 @@ body.admin {
|
|||
width:40px;
|
||||
font-size:0px;
|
||||
color:$win95-bg;
|
||||
|
||||
background-image: url("../images/start.png");
|
||||
|
||||
background-image: url("../images/start.png");
|
||||
background-repeat:no-repeat;
|
||||
background-position:8%;
|
||||
background-clip:padding-box;
|
||||
|
@ -723,7 +728,7 @@ body.admin {
|
|||
}
|
||||
|
||||
.drawer__header a:first-child:hover {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAOCAIAAACpTQvdAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAF3pUWHRBdXRob3IAAAiZS84oys9LzAEAC5oC6A7BY/IAAACWSURBVCiRhVJJDsQgDEuqOfRZ7a1P5gbP4uaJaEjTADMWQhHYjlk4p0wLnNdptdF4KvBUDyGzVwc2xO+uKtH+1o0ytEEmqFpuxlvFCGCxKbNIT56QCi2MzaA/2Mz+mERSOeqzJG2RUxkjdTabgPtFoZ1bZxcKvgPcLZVufAyR9Ni8v5dWDzfFx0giC1RvZFv6l35QQ/Mvv39XXgGzQpoAAAAASUVORK5CYII=");
|
||||
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;
|
||||
|
@ -732,7 +737,7 @@ body.admin {
|
|||
}
|
||||
|
||||
.drawer__tab:first-child {
|
||||
|
||||
|
||||
}
|
||||
|
||||
.search {
|
||||
|
@ -844,7 +849,7 @@ body.admin {
|
|||
padding:4px 8px;
|
||||
}
|
||||
|
||||
.privacy-dropdown.active
|
||||
.privacy-dropdown.active
|
||||
.privacy-dropdown__value {
|
||||
background: $win95-bg;
|
||||
box-shadow:unset;
|
||||
|
@ -935,7 +940,7 @@ body.admin {
|
|||
background-color:$win95-bg;
|
||||
border:1px solid black;
|
||||
box-sizing:content-box;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.emoji-dialog .emoji-search {
|
||||
|
@ -1010,8 +1015,8 @@ body.admin {
|
|||
width:60px;
|
||||
font-size:0px;
|
||||
color:$win95-bg;
|
||||
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAOCAIAAACpTQvdAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAF3pUWHRBdXRob3IAAAiZS84oys9LzAEAC5oC6A7BY/IAAACWSURBVCiRhVJJDsQgDEuqOfRZ7a1P5gbP4uaJaEjTADMWQhHYjlk4p0wLnNdptdF4KvBUDyGzVwc2xO+uKtH+1o0ytEEmqFpuxlvFCGCxKbNIT56QCi2MzaA/2Mz+mERSOeqzJG2RUxkjdTabgPtFoZ1bZxcKvgPcLZVufAyR9Ni8v5dWDzfFx0giC1RvZFv6l35QQ/Mvv39XXgGzQpoAAAAASUVORK5CYII=");
|
||||
|
||||
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;
|
||||
|
@ -1049,40 +1054,40 @@ body.admin {
|
|||
}
|
||||
}
|
||||
|
||||
.column-link[href="/web/timelines/public"] {
|
||||
background-image: url("../images/icon_public.png");
|
||||
.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");
|
||||
.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");
|
||||
.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");
|
||||
.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");
|
||||
.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");
|
||||
.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");
|
||||
.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");
|
||||
.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");
|
||||
.column-link[href="/auth/sign_out"] {
|
||||
background-image: url("../images/icon_logout.png");
|
||||
&:hover { background-image: url("../images/icon_logout.png"); }
|
||||
}
|
||||
|
||||
|
@ -1098,7 +1103,7 @@ body.admin {
|
|||
line-height:30px;
|
||||
padding-left:20px;
|
||||
padding-right:40px;
|
||||
|
||||
|
||||
left:0px;
|
||||
bottom:-30px;
|
||||
display:block;
|
||||
|
@ -1106,9 +1111,9 @@ body.admin {
|
|||
background-color:#7f7f7f;
|
||||
width:200%;
|
||||
height:30px;
|
||||
|
||||
|
||||
-ms-transform: rotate(-90deg);
|
||||
|
||||
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
transform-origin:top left;
|
||||
|
@ -1189,7 +1194,7 @@ body.admin {
|
|||
left:unset;
|
||||
}
|
||||
|
||||
.dropdown > .icon-button, .detailed-status__button > .icon-button,
|
||||
.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 */
|
||||
|
@ -1239,8 +1244,8 @@ body.admin {
|
|||
background:$win95-bg;
|
||||
}
|
||||
|
||||
.actions-modal::before,
|
||||
.boost-modal::before,
|
||||
.actions-modal::before,
|
||||
.boost-modal::before,
|
||||
.confirmation-modal::before,
|
||||
.report-modal::before {
|
||||
content: "Confirmation";
|
||||
|
@ -1278,8 +1283,8 @@ body.admin {
|
|||
.confirmation-modal__cancel-button {
|
||||
color:black;
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:active,
|
||||
&:focus,
|
||||
&:hover {
|
||||
color:black;
|
||||
}
|
||||
|
@ -1566,10 +1571,10 @@ a.table-action-link:hover,
|
|||
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 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;
|
||||
|
@ -1580,8 +1585,8 @@ a.table-action-link:hover,
|
|||
}
|
||||
}
|
||||
|
||||
.simple_form button,
|
||||
.simple_form .button,
|
||||
.simple_form button,
|
||||
.simple_form .button,
|
||||
.simple_form .block-button
|
||||
{
|
||||
background: $win95-bg;
|
||||
|
@ -1608,8 +1613,8 @@ a.table-action-link:hover,
|
|||
}
|
||||
}
|
||||
|
||||
.simple_form button.negative,
|
||||
.simple_form .button.negative,
|
||||
.simple_form button.negative,
|
||||
.simple_form .button.negative,
|
||||
.simple_form .block-button.negative
|
||||
{
|
||||
background: $win95-bg;
|
||||
|
@ -1631,8 +1636,8 @@ a.table-action-link:hover,
|
|||
border-right-color:#f5f5f5;
|
||||
width:12px;
|
||||
height:12px;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
margin-right:2px;
|
||||
}
|
||||
|
||||
|
|
|
@ -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…
Reference in a new issue