From d6d4a5ba4a41e9218bfd58cab64e337da03a226e Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Fri, 15 Mar 2019 02:16:15 -0400 Subject: [PATCH] FEATURE: support custom icons in themes (#7155) * First take * Add support for sprites in themes Automatically register any custom icons added via themes or plugins * Fix theme sprite caching * Simplify test * Update lib/svg_sprite/svg_sprite.rb Co-Authored-By: pmusaraj * Fix /svg-sprite/search request --- app/controllers/svg_sprite_controller.rb | 15 +++--- app/models/theme_field.rb | 1 + lib/svg_sprite/svg_sprite.rb | 52 ++++++++++++++++--- lib/upload_creator.rb | 1 + spec/components/svg_sprite/svg_sprite_spec.rb | 13 +++++ .../images/custom-theme-icon-sprite.svg | 6 +++ spec/requests/svg_sprite_controller_spec.rb | 18 +++++++ 7 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 spec/fixtures/images/custom-theme-icon-sprite.svg diff --git a/app/controllers/svg_sprite_controller.rb b/app/controllers/svg_sprite_controller.rb index 266db140138..a3c5cf458a7 100644 --- a/app/controllers/svg_sprite_controller.rb +++ b/app/controllers/svg_sprite_controller.rb @@ -27,13 +27,16 @@ class SvgSpriteController < ApplicationController end def search - keyword = params.require(:keyword) - data = SvgSprite.search(keyword) + RailsMultisite::ConnectionManagement.with_hostname(params[:hostname]) do - if data.blank? - render body: nil, status: 404 - else - render plain: data.inspect, disposition: nil, content_type: 'text/plain' + keyword = params.require(:keyword) + data = SvgSprite.search(keyword) + + if data.blank? + render body: nil, status: 404 + else + render plain: data.inspect, disposition: nil, content_type: 'text/plain' + end end end end diff --git a/app/models/theme_field.rb b/app/models/theme_field.rb index a591a6e9cb6..5a1e36c46d6 100644 --- a/app/models/theme_field.rb +++ b/app/models/theme_field.rb @@ -9,6 +9,7 @@ class ThemeField < ActiveRecord::Base after_commit do |field| SvgSprite.expire_cache if field.target_id == Theme.targets[:settings] + SvgSprite.expire_cache if field.name == SvgSprite.theme_sprite_variable_name end scope :find_by_theme_ids, ->(theme_ids) { diff --git a/lib/svg_sprite/svg_sprite.rb b/lib/svg_sprite/svg_sprite.rb index f6946b2e325..2ccb63cb5e1 100644 --- a/lib/svg_sprite/svg_sprite.rb +++ b/lib/svg_sprite/svg_sprite.rb @@ -189,8 +189,28 @@ module SvgSprite FA_ICON_MAP = { 'far fa-' => 'far-', 'fab fa-' => 'fab-', 'fas fa-' => '', 'fa-' => '' } - SVG_SPRITE_PATHS = Dir.glob(["#{Rails.root}/vendor/assets/svg-icons/**/*.svg", - "#{Rails.root}/plugins/*/svg-icons/*.svg"]) + CORE_SVG_SPRITES = Dir.glob("#{Rails.root}/vendor/assets/svg-icons/**/*.svg") + + THEME_SPRITE_VAR_NAME = "icons-sprite" + + def self.custom_svg_sprites(theme_ids = []) + custom_sprite_paths = Dir.glob("#{Rails.root}/plugins/*/svg-icons/*.svg") + + ThemeField.where(type_id: ThemeField.types[:theme_upload_var], name: THEME_SPRITE_VAR_NAME, theme_id: Theme.transform_ids(theme_ids)) + .pluck(:upload_id).each do |upload_id| + + upload = Upload.find(upload_id) + original_path = Discourse.store.path_for(upload) + if original_path.blank? + external_copy = Discourse.store.download(upload) rescue nil + original_path = external_copy.try(:path) + end + + custom_sprite_paths << Discourse.store.path_for(upload) if original_path.present? + end + + custom_sprite_paths + end def self.all_icons(theme_ids = []) get_set_cache("icons_#{Theme.transform_ids(theme_ids).join(',')}") do @@ -200,6 +220,7 @@ module SvgSprite .merge(badge_icons) .merge(group_icons) .merge(theme_icons(theme_ids)) + .merge(custom_icons(theme_ids)) .delete_if { |i| i.blank? || i.include?("/") } .map! { |i| process(i.dup) } .merge(SVG_ICONS) @@ -221,11 +242,13 @@ module SvgSprite cache&.clear end + def self.sprite_sources(theme_ids) + CORE_SVG_SPRITES | custom_svg_sprites(theme_ids) + end + def self.bundle(theme_ids = []) icons = all_icons(theme_ids) - doc = File.open("#{Rails.root}/vendor/assets/svg-icons/fontawesome/solid.svg") { |f| Nokogiri::XML(f) } - svg_subset = """