Using the color-tools gem for theme support
When offering branding options to your customers/users, neither a cusomizable CSS stylesheet nor Liquid is unobtrusive from an integration or usability perspective.
Fall back to your design roots
A standard 3 color palette composed of a
- dominant color
- interactive color ( complement to your dominant color scheme )
- tonic color ( highlights and accents )
requires exactly 3 inputs from your customer/user from which a gradient based scheme can be generated server side for each of the above colors.
Requirements
Austin Ziegler's color-tools gem ( bundled as a dependency when installing pdf-writer ) already implements most of the required functionality.
Install with
sudo gem install color-tools
Parsing hexadecimal (HTML) color values
module Format
EMAIL = /^[_a-z0-9\+\.\-]+\@[_a-z0-9\-]+\.[_a-z0-9\.\-]+$/i
HTTP_URI = /^https?:\/\/\S+$/
HEX_COLOR = /(#)([a-fA-F0-9][a-fA-F0-9])([a-fA-F0-9][a-fA-F0-9])([a-fA-F0-9][a-fA-F0-9])/
end
Format::HEX_COLOR should match the 6 and 7 digit hex color variations eg. #CCCCCC and CCCCCC
The Theme model
class Theme < ActiveRecord::Base
set_table_name 'themes'
belongs_to :account
validates_presence_of :title, :dominant_color, :interactive_color, :tonic_color
validates_format_of :dominant_color, :with => Format::HEX_COLOR, :message => ' is not a valid HEX color.'.t
validates_format_of :interactive_color, :with => Format::HEX_COLOR , :message => ' is not a valid HEX color.'.t
validates_format_of :tonic_color, :with => Format::HEX_COLOR , :message => ' is not a valid HEX color.'.t
validates_uniqueness_of :title, :scope => 'account_id'
validates_presence_of :active, :in => 0..1
serialize :dominant, Array
serialize :interactive, Array
serialize :tonic, Array
delegate :to_s, :to => :title
class << self
def suggested_colors
Color::RGB::constants.reject{|c| %w(PDF_FORMAT_STR Metallic).include? c }.collect!{|c| eval("Color::RGB::#{c}").html}
end
def color_to_palette( color )
Color::Palette::MonoContrast.new( Color::RGB.from_html( color ) ).background.to_a.collect!{|c| [c.first, c.last.html] }
end
end
def to_param; "#{self.id}-#{self.title.to_url}" end
def generate_color_scheme!
%w(dominant interactive tonic).each do |c|
self.send("#{c}=".to_sym, Theme.color_to_palette( self.send("#{c}_color") ) )
end
end
def active?() self.active == 1 end
def activate!
return if self.active?
Theme.transaction do
self.account.themes.update_all("themes.active = '0'")
self.update_attribute(:active, '1')
end
end
def before_destroy; !self.active? end
end
Theme observer
class ThemeObserver < ActiveRecord::Observer
def before_validation( theme )
theme.active = 0 unless theme.attribute_present?(:active)
end
def before_save( theme ) theme.generate_color_scheme! end
end
Console examples
Shamelessly rip these common colors from color-tools.
>> Theme.suggested_colors
=> ["#cd853f", "#f8f8ff", "#333333", "#ffffe0", "#dc143c", "#a0522d", "#f0e68c", "#e6e6e6", "#48d1cc", "#ff8c00", "#696969", "#ee82ee", "#ffa07a", "#a52a2a", "#da70d6", "#008000", "#808080", "#800000", "#b8860b", "#ff0000", "#708090", "#add8e6", "#f0f8ff", "#ffe4b5", "#8fbc8f", "#9acd32", "#778899", "#d2691e", "#db7093", "#fffaf0", "#ff69b4", "#b3b3b3", "#9370db", "#8b008b", "#f4a460", "#d3d3d3", "#f5f5dc", "#6b8e23", "#9400d3", "#008080", "#4d4d4d", "#00ff00", "#00ffff", "#ffc0cb", "#ffd700", "#c71585", "#9932cc", "#c0c0c0", "#0000ff", "#e6e6fa", "#ffa07a", "#deb887", "#eee8aa", "#1e90ff", "#d02090", "#000000", "#66cdaa", "#a9a9a9", "#bc8f8f", "#adff2f", "#808080", "#ffdead", "#483d8b", "#fffafa", "#f08080", "#faebd7", "#ff7f50", "#ffefd5", "#228b22", "#1a1a1a", "#778899", "#3cb371", "#556b2f", "#2e8b57", "#cd5c5c", "#cccccc", "#6b8e23", "#ff1493", "#d8bfd8", "#90ee90", "#ffe4c4", "#dda0dd", "#daa520", "#4d4d4d", "#32cd32", "#00008b", "#8b0000", "#87ceeb", "#fff0f5", "#191970", "#eee8aa", "#d19275", "#f5deb3", "#20b2aa", "#deb887", "#4169e1", "#808080", "#999999", "#66cdaa", "#006400", "#00ff7f", "#e0ffff", "#00ffff", "#000080", "#2f4f4f", "#ff00ff", "#1a1a1a", "#b0c4de", "#6495ed", "#ffdab9", "#556b2f", "#7b68ee", "#fff5ee", "#4b0082", "#cccccc", "#00bfbf", "#ffebcd", "#d3d3d3", "#ffa500", "#ff6347", "#daa520", "#008b8b", "#faf0e6", "#b0e0e6", "#666666", "#e9967a", "#7cfc00", "#f5fffa", "#6a5acd", "#b22222", "#5f9ea0", "#87cefa", "#98fb98", "#f5f5f5", "#f0fff0", "#a9a9a9", "#0000cd", "#8b4513", "#999999", "#fafad2", "#2f4f4f", "#7fffd4", "#fdf5e6", "#4682b4", "#dcdcdc", "#fff8dc", "#b0c4de", "#ffdab9", "#333333", "#fffff0", "#ff8c00", "#00fa9a", "#fff5ee", "#e6e6e6", "#ffb6c1", "#696969", "#8a2be2", "#ff4500", "#40e0d0", "#ff00ff", "#808080", "#b8860b", "#800080", "#ffffff", "#666666", "#fffacd", "#e9967a", "#ffe4e1", "#708090", "#7fff00", "#8470ff", "#b22222", "#afeeee", "#ffff00", "#ba55d3", "#f0fff0", "#bdb76b", "#fa8072", "#b3b3b3", "#f0ffff", "#fafad2", "#00ced1", "#808000", "#d2b48c"]
Visualizing generated palettes from a saved model.
>> t = Theme.find(1)
>> t.dominant_color
=> "#BBCC44"
>> t.dominant
=> [[5, "#ecf7f8"], [0, "#44aabb"], [-2, "#33808c"], [1, "#60b7c5"], [-1, "#3a919f"], [2, "#73bfcc"], [-5, "#071113"], [3, "#a2d4dd"], [-4, "#112b2f"], [4, "#d0eaee"], [-3, "#22555e"]]
>> t.interactive_color
=> "#44AABB"
>> t.interactive
=> [[5, "#ecf7f8"], [0, "#44aabb"], [-2, "#33808c"], [1, "#60b7c5"], [-1, "#3a919f"], [2, "#73bfcc"], [-5, "#071113"], [3, "#a2d4dd"], [-4, "#112b2f"], [4, "#d0eaee"], [-3, "#22555e"]]
>> t.tonic_color
=> "#CC6644"
>> t.tonic
=> [[5, "#faf0ec"], [0, "#cc6644"], [-2, "#994d33"], [1, "#d47d60"], [-1, "#ad573a"], [2, "#d98c73"], [-5, "#140a07"], [3, "#e6b3a2"], [-4, "#331a11"], [4, "#f2d9d0"], [-3, "#663322"]]
Each color palette is an Array, with 11 items.
- indexes -1 to -5 : 5 darker shades of the original color
- index 0 : the original color
- index 1 to 5 : lighter shades of the orginal color
Injecting to the view
There's two easy ways to reflect this in your view ...
- Inline style declaration, overriding color values defined in external stylesheets
- Use a seperate CSS controller, set content type to text/css and reference in your document head like any other external stylesheets (and the purists are happy too)
1 comment
Jump to comment form | comments rss [?]