// Variables
$font-size: 12px;
// Nested rules
#foo {
.bar {
font-size: $font-size;
}
}
// Include other Sass style sheets
@import 'bar';
// Mixins
@mixin has-cats {
&::before {
content: 'meow';
display: block;
}
}
#internet {
@include has-cats;
}
// _my-ui.scss
#foo {
background: nth($palette, 1);
color: nth($palette, 2);
}
// palette1.scss
$palette: (red green);
@import 'my-ui';
// palette2.scss
$palette: (blue yellow);
@import 'my-ui';
// dynamic-palette.scss
$palette: get-dynamic-palette();
@import 'my-ui';
# config/initializers/sass.rb
module Sass::Script::Functions
def get_dynamic_palette
palette = 2.times.map do
color = '#%06x' % (rand * 0xffffff)
Sass::Script::Value::Color.from_hex(color)
end
Sass::Script::Value::List.new(palette, :space)
end
end
// app/assets/stylesheets/dynamic-palette-rails.css.scss
$palette: get-dynamic-palette-from-user-somehow-magically();
@import 'my-ui';
# sass-rails/lib/sass/rails/template.rb
module Sass
module Rails
class SassTemplate < Tilt::Template
# ...
def evaluate(context, locals, &block)
cache_store = CacheStore.new(context.environment)
options = {
:filename => eval_file,
:line => line,
:syntax => syntax,
:cache_store => cache_store,
:importer => importer_class.new(context.pathname.to_s),
:load_paths => context.environment.paths.map { |path| importer_class.new(path.to_s) },
:sprockets => {
:context => context,
:environment => context.environment
}
}
sass_config = context.sass_config.merge(options)
engine = ::Sass::Engine.new(data, sass_config)
css = engine.render
engine.dependencies.map do |dependency|
context.depend_on(dependency.options[:filename])
end
css
rescue ::Sass::SyntaxError => e
context.__LINE__ = e.sass_backtrace.first[:line]
raise e
end
# ...
end
end
end
Sass::Engine
# lib/sass_custom_palette.rb
class SassCustomPalette
TEMPLATE = <<-EOS.freeze
$palette: get-custom-palette();
@import 'my-ui';
EOS
def initialize(color)
@color = color
end
def render
Sass::Engine.new(TEMPLATE, sass_custom_options).render
end
private
def sass_custom_options
{ syntax: :scss,
style: :expanded,
custom: { color: @color } }
end
end
# config/initializers/sass.rb
module Sass::Script::Functions
def get_custom_palette
color = Sass::Script::Value::Color.from_hex(
options[:custom][:color]
)
factor = Sass::Script::Value::Number.new(20, '%')
palette = [
lighten(color, factor),
darken(color, factor)
]
Sass::Script::Value::List.new(palette, :space)
end
end
# app/controllers/palettes_controller.rb
class PalettesController < ApplicationController
def custom_palette
custom_renderer = SassCustomPalette.new(
params[:custom_color]
)
@css = custom_renderer.render
end
end
-# app/views/palettes/custom_palette.css.haml
= @css.html_safe
Sass::SyntaxError - File to import not found or unreadable: my-ui.
-__-
class SassCustomPalette
private
def load_paths
root = Rails.root.join('app', 'assets', 'stylesheets')
Dir[root.join('includes')]
end
def sass_custom_options
{ syntax: :scss,
style: :expanded,
load_paths: load_paths,
custom: { color: @color } }
end
end
// app/assets/stylesheets/includes/_my-ui.scss
#foo {
background: nth($palette, 1);
color: nth($palette, 2);
}
[memcached.org](http://memcached.org) / [github.com/mperham/dalli](https://github.com/mperham/dalli)
# config/environments/production.rb
config.cache_store = :mem_cache_store, \
MEM_CACHE_SERVER, MEM_CACHE_OPTIONS
Rails.cache.write('foo', 'bar')
Rails.cache.fetch('foo') #=> 'bar'
class SassRenderer
def initialize(template, cache_key, options)
@cache_key = cache_key
@engine = Sass::Engine.new(template, options)
end
def render
from_cache { @engine.render }
end
def cached?
Rails.cache.exist?(@cache_key)
end
def get_cached_css
Rails.cache.fetch(@cache_key)
end
private
def set_cached_css(css)
Rails.cache.write(@cache_key, css)
end
def from_cache(&write_block)
get_cached_css || write_block.call.tap { |css| set_cached_css(css) }
end
end
SassCustomPalette
class SassCustomPalette
def initialize(color)
@color = color
@cache_key = "custom_palette/#{@color}"
@engine = SassRenderer.new(
TEMPLATE, @cache_key, sass_custom_options
)
end
delegate :render, to: :@engine
end
# app/workers/sass_custom_palette_worker.rb
class SassCustomPaletteWorker
include Sidekiq::Worker
def perform(color)
SassCustomPalette.new(color).render
end
end
class SassCustomPalette
def render_async
unless @engine.cached?
SassCustomPaletteWorker.peform_async(@color)
end
@cache_key
end
end
class SassRenderer
def self.get_by_key(key)
Rails.cache.fetch(key)
end
def self.cached?(key)
Rails.cache.exist?(key)
end
private
def get_cached_css
self.class.get_by_key(@cache_key)
end
end
class PalettesController < ApplicationController
def request_custom_palette
custom_renderer = SassCustomPalette.new(
params[:custom_color]
)
@key = custom_renderer.render_async
end
def check_custom_palette
@ready = SassRenderer.cached?(params[:key])
end
def custom_palette
@css = SassRenderer.get_by_key(params[:key])
end
end
Slides: | sassy-talk.jeremyfairbank.com |
Demo Source: | github.com/jfairbank/dynamically-sassy-demos |
Blog: | blog.jeremyfairbank.com |
@elpapapollo
jeremy@pushagency.io
github.com/jfairbank