# Bootswatch themes are free themes for bootstrap available at https://bootswatch.com/. # For every bootswatch theme we have one card of card type "bootswatch skin". # They all have codenames following the pattern "#{theme_name}_skin". # # The original bootswatch theme is build from two files, `_variables.scss` and # `_bootswatch.scss`. The original bootstrap scss has to be put between those two. # `_variables.scss` overrides bootstrap variables, `_bootswatch.scss` overrides # bootstrap css (bootstrap's SCSS variables are defined later with `!default`, so the # bootswatch value takes precendence. # # The content of a bootswatch theme card consists of four parts: # * functions: hard-coded SCSS mixins and functions available to variables # * variables: variables from the bootswatch them and (where applicable) user-customized # variables including colors. # * main: the core bootstrap scss and all the SCSS from mods # * stylesheets: the content from `_bootswatch.scss` and any user overrides # # Thus Bootswatch Skins bring together code from many different places: # # - code file cards like "bootstrap function" and "bootstrap core" # - directly from files in the bootswatch submodule # - asset/style directories in mods # - user-editable fields, like +:colors, +:variables, and +:stylesheets # # All these sources need access to the shared SCSS variables, so unlike JavaScript assets, # they cannot be processed independently on a context-free per-mod basis. include_set Abstract::AssetInputter, input_format: :css, input_view: :compressed include_set Abstract::Scss include_set Abstract::SkinBox basket[:non_createable_types] << :bootswatch_skin card_accessor :colors, type: :scss card_accessor :variables, type: :scss card_accessor :stylesheets, type: :skin card_accessor :parent, type: :pointer CONTENT_PARTS = %i[pre_variables variables post_variables stylesheets].freeze PRE_VARIABLES_CARD_NAMES = %i[bootstrap_functions].freeze POST_VARIABLES_CARD_NAMES = %i[bootstrap_core style_mods].freeze def content CONTENT_PARTS.map do |n| send "#{n}_content" end.join "\n" end def item_names _args={} (PRE_VARIABLES_CARD_NAMES + variables_card_names + POST_VARIABLES_CARD_NAMES + stylesheets_card_names).compact.map do |n| Codename.name n end.compact end def parent? parent_skin_card&.real? end def theme_name theme_codename.to_s.sub(/_skin$/, "") end def theme_card @theme_card ||= parent? && parent_skin_card.id != id ? parent_skin_card.theme_card : self end def theme_codename theme_card.codename end def scss_from_theme_file file path = ::File.join source_dir, "_#{file}.scss" path && ::File.exist?(path) ? ::File.read(path) : "" end def editable_item_cards [colors_card, variables_card, stylesheets_card] end def variables_card_names %i[colors variables].map { |s| [name, s].cardname } end def stylesheets_card_names [[name, :stylesheets].cardname] end def content_from_theme field theme_card&.scss_from_theme_file field end def read_bootstrap_variables ::File.read ::File.expand_path( "#{mod_path :bootstrap}/vendor/bootstrap/scss/_variables.scss" ) end format :html do view :input do if card.parent? super() else "Content is stored in file and can't be edited." end end def edit_fields [[:colors, { title: "" }], [:variables, { title: "Variables" }], [:stylesheets, { title: "Styles" }]] end view :one_line_content do "" end end private def parent_skin_card parent_card&.first_card end # needed to make the refresh_script_and_style method work with these cards def source_files item_cards.map do |i_card| i_card.try(:source_files) end.flatten.compact end # needed to make the Assets.refresh method work with these cards def existing_source_paths item_cards.map do |i_card| i_card.try(:existing_source_paths) end.flatten.compact end def pre_variables_content load_content(*PRE_VARIABLES_CARD_NAMES) end def variables_content [ load_content(variables_card_names), theme_card.scss_from_theme_file(:variables) ].compact.join "\n" end def post_variables_content load_content(*POST_VARIABLES_CARD_NAMES) end def stylesheets_content [ theme_card.scss_from_theme_file(:bootswatch), load_content(stylesheets_card_names) ].compact.join "\n" end def combined_content filename, cardnames [theme_card.scss_from_theme_file(filename), load_content(cardnames)].compact.join "\n" end def load_content *names cards = names.flatten.map do |n| Card.fetch(n)&.recursed_item_cards end cards.flatten.compact.map(&:content).join "\n" end def source_dir @source_dir ||= ::File.expand_path( "#{mod_path :bootstrap}/vendor/bootswatch/dist/#{theme_name}", __FILE__ ) end event :use_as_current_skin, :finalize, on: :save, trigger: :required do style_rule = Card[:all, :style] style_rule.content = name style_rule.save! end