Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Spree Themer's Toolkit

A Spree Themer's Toolkit

My slides from Spreeconf 2012

Wynn Netherland

February 16, 2012
Tweet

More Decks by Wynn Netherland

Other Decks in Programming

Transcript

  1. having two or more independent but harmonically related melodic parts

    sounding together pol·y·phon·ic adjective:
  2. Extensions refer to discrete packages of code that provide new

    functionality to a Spree application, while extensions may affect the appearance of a Spree application they generally only provide additional interfaces to enable users to interact with the new functionality provided.
  3. Extensions refer to discrete packages of code that provide new

    functionality to a Spree application, while extensions may affect the appearance of a Spree application they generally only provide additional interfaces to enable users to interact with the new functionality provided.
  4. Themes are discrete packages of code that only affect the

    appearance of a Spree application (and generally only the front-end store). Themes do not generally include any logic customizations.
  5. Themes are discrete packages of code that only affect the

    appearance of a Spree application (and generally only the front-end store). Themes do not generally include any logic customizations.
  6. drwxr-xr-x 17 wynn staff 578 Nov 2 08:36 . drwxr-xr-x

    8 wynn staff 272 Nov 2 08:35 .. drwxr-xr-x 16 wynn staff 544 Nov 2 08:36 admin -rw-r--r-- 1 wynn staff 155 Nov 2 08:30 application.css -rw-r--r-- 1 wynn staff 143 Nov 2 08:30 application.css.gz drwxr-xr-x 7 wynn staff 238 Nov 2 08:36 creditcards drwxr-xr-x 3 wynn staff 102 Nov 2 08:36 datepicker -rw-r--r-- 1 wynn staff 1150 Nov 2 08:19 favicon.ico drwxr-xr-x 6 wynn staff 204 Nov 2 08:36 icons drwxr-xr-x 4 wynn staff 136 Nov 2 08:36 jqPlot drwxr-xr-x 15 wynn staff 510 Nov 2 08:36 jquery-ui drwxr-xr-x 3 wynn staff 102 Nov 2 08:35 jquery.alerts drwxr-xr-x 3 wynn staff 102 Nov 2 08:35 jquery.jstree -rw-r--r-- 1 wynn staff 6694 Nov 2 08:36 manifest.yml drwxr-xr-x 5 wynn staff 170 Nov 2 08:36 noimage -rw-r--r-- 1 wynn staff 1608 Nov 2 08:19 spinner.gif drwxr-xr-x 6 wynn staff 204 Nov 2 08:36 store
  7. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d .

    ├── app │ ├── assets │ │ ├── images │ │ │ └── store │ │ │ └── icons │ │ ├── javascripts │ │ │ └── store │ │ └── stylesheets │ │ └── store │ ├── overrides │ └── views │ └── spree │ ├── shared │ └── wishlists ├── lib │ └── generators │ └── spree_rdr_theme │ └── install └── vendor └── assets ├── images │ └── fancybox ├── javascripts └── stylesheets
  8. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d .

    ├── app │ ├── assets │ │ ├── images │ │ │ └── store │ │ │ └── icons │ │ ├── javascripts │ │ │ └── store │ │ └── stylesheets │ │ └── store │ ├── overrides │ └── views │ └── spree │ ├── shared │ └── wishlists ├── lib │ └── generators │ └── spree_rdr_theme │ └── install └── vendor └── assets ├── images │ └── fancybox ├── javascripts └── stylesheets Your stuff
  9. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d .

    ├── app │ ├── assets │ │ ├── images │ │ │ └── store │ │ │ └── icons │ │ ├── javascripts │ │ │ └── store │ │ └── stylesheets │ │ └── store │ ├── overrides │ └── views │ └── spree │ ├── shared │ └── wishlists ├── lib │ └── generators │ └── spree_rdr_theme │ └── install └── vendor └── assets ├── images │ └── fancybox ├── javascripts └── stylesheets Your Stylesheets, images, JavaScripts
  10. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d .

    ├── app │ ├── assets │ │ ├── images │ │ │ └── store │ │ │ └── icons │ │ ├── javascripts │ │ │ └── store │ │ └── stylesheets │ │ └── store │ ├── overrides │ └── views │ └── spree │ ├── shared │ └── wishlists ├── lib │ └── generators │ └── spree_rdr_theme │ └── install └── vendor └── assets ├── images │ └── fancybox ├── javascripts └── stylesheets Your Deface overrides
  11. Deface::Override.new(:virtual_path => "posts/_form", :name => "example-1", :replace => "h1", :text

    => "<h1>New Post</h1>") Deface::Override.new(:virtual_path => "posts/_form", :name => "example-1", :replace => "h1") do "<h1>New Post</h1>" end In a block
  12. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d .

    ├── app │ ├── assets │ │ ├── images │ │ │ └── store │ │ │ └── icons │ │ ├── javascripts │ │ │ └── store │ │ └── stylesheets │ │ └── store │ ├── overrides │ └── views │ └── spree │ ├── shared │ └── wishlists ├── lib │ └── generators │ └── spree_rdr_theme │ └── install └── vendor └── assets ├── images │ └── fancybox ├── javascripts └── stylesheets Your custom views
  13. spree_rdr_theme [ master: ✔ ] 6d ⚡ tree -d .

    ├── app │ ├── assets │ │ ├── images │ │ │ └── store │ │ │ └── icons │ │ ├── javascripts │ │ │ └── store │ │ └── stylesheets │ │ └── store │ ├── overrides │ └── views │ └── spree │ ├── shared │ └── wishlists ├── lib │ └── generators │ └── spree_rdr_theme │ └── install └── vendor └── assets ├── images │ └── fancybox ├── javascripts └── stylesheets Third party libraries and frameworks
  14. A person having a speaking, reading, or writing knowledge of

    several languages pol·y·glot adjective:
  15. * E .class #id E F E > F E

    + F E[attribute] E[attribute=value] E[attribute~=value] E[attribute|=value] :first-child :link :visited :lang() :before ::before :after ::after :first-letter ::first-letter :first-line ::first-line E[attribute^=value] E[attribute$=value] E[attribute*=value] E ~ F :root :last-child :only-child :nth-child() :nth-last-child() :first-of-type :last-of-type :only-of-type :nth-of-type() :nth-last-of-type() :empty :not() :target :enabled :disabled :checked CSS3 selectors (and some golden oldies) :header Steal this from jQuery, please
  16. table.users { tr { td { background: #d1d1d; a {

    color: #111; } } } } Nested rules - selectors
  17. table.users { tr { td { color: #111; &.alt {

    color: #333; } &:hover { color: #666; } } } } Nested rules - selectors
  18. table.users { tr { td { background: #d1d1d; a {

    color: #111; } } } } Syntax options - SCSS Sassy CSS!
  19. .user { background: #333; border-size: 2px; } .owner { background:

    #333; border-size: 2px; } .admin { background: #666; border-size: 4px; } Variables
  20. $gray: #333; $default_border: 2px; .user { background: $gray; border-size: $default_border;}

    .owner { background: $gray; border-size: $default_border;} .admin { background: $gray + #333; border-size: $default_border + 2px; } Variables Even math! and color mixing!
  21. .avatar { padding: 2px; border: solid 1px #ddd; position: absolute;

    top: 5px; left: 5px; } p img { padding: 2px; border: solid 1px #ddd; } Mixins
  22. @mixin frame($padding_width: 2px, $border_color: #ddd) { padding: $padding_width; border: {

    width: 1px; style: solid; color $border_color; } } .avatar { @include frame; position: absolute; top: 5px; left: 5px; } p img { @include frame(1px, #ccc);} Mixins defines the mixin mixes in the rules
  23. .flash { padding: 5px; border-width: 1px; font-weight: bold; } .error

    { color: #8a1f11; background: #fbe3e4; } .notice { color: #514721; background: #fff6bf; } Mixins
  24. .flash { padding: 5px; border-width: 1px; font-weight: bold; } .error

    { @extend .flash; color: #8a1f11; background: #fbe3e4; } .notice { @extend .flash; color: #514721; background: #fff6bf; } Mixins
  25. .flash, .error, .notice { padding: 5px; border-width: 1px; font-weight: bold;

    } .error { color: #8a1f11; background: #fbe3e4; } .notice { color: #514721; background: #fff6bf; } Mixins now we can use a single class in our markup
  26. @import "reset.scss" # _reset.scss @import "typography" # _typography.scss @import "layout.css"

    # url(layout.css) Imports Included at compile time - just one http request
  27. “It’s time to abolish all vendor prefixes. They’ve become solutions

    for which there is no problem, and they are actively harming web standards.” — Peter-Paul Koch aka @ppk http://www.quirksmode.org/blog/archives/2010/03/css_vendor_pref.html
  28. @import "compass/css3.scss"; .callout { @include border-radius(5px); @include linear-gradient("left top", "left

    bottom", #fff, #ddd); } .callout { -moz-border-radius: 5px; -webkit-border-radius: 5px; -border-radius: 5px; background-image: -moz-linear-gradient(top, bottom, from(#fff), to(#ddd)); background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0.00, #fff), color-stop(1.00, #ddd)); } Compass CSS3 mixins very different syntax
  29. “Well, reactions to my proposal to abolish vendor prefixes are

    mixed, and I might have overshot my target here.” -Peter-Paul Koch aka @ppk http://www.quirksmode.org/blog/archives/2010/03/css_vendor_pref_1.html
  30. <div id= "wrapper" class="container"> <div id="content" class="span-7 prepend-1"> <div id="main">

    ... </div> <div id="featured" class="span-5 last"> ... </div> </div> <div id="sidebar" class="span-3 append-1 last"> ... </div> </div> </div> A Blueprint example boo? / Yay?
  31. #wrapper { @include container; #content { @include column(7); @include append(1);

    #featured { @include column(5, true); } } #sidebar { @include column(3, true); @include prepend(1); } } A Blueprint example
  32. hue(#cc3) => 60deg saturation(#cc3) => 60% lightness(#cc3) => 50% adjust-hue(#cc3,

    20deg) => #9c3 saturate(#cc3, 10%) => #d9d926 desaturate(#cc3, 10%) => #bfbf40 lighten(#cc3, 10%) => #d6d65c darken(#cc3, 10%) => #a3a329 grayscale(#cc3) => desaturate(#cc3, 100%) = #808080 complement(#cc3) => adjust-hue(#cc3, 180deg) = #33c mix(#cc3, #00f) => #e56619 mix(#cc3, #00f, 10%) => #f91405 mix(#cc3, #00f, 90%) => #d1b72d Sass 2.4 color functions http://nex-3.com/posts/89-powerful-color-manipulation-with-sass
  33. mix(rgba(51, 255, 51, 0.75), #f00) => rgba(178, 95, 19, 0.875)

    mix(rgba(51, 255, 51, 0.90), #f00) => rgba(163, 114, 22, 0.95) alpha(rgba(51, 255, 51, 0.75)) => 0.75 opacity(rgba(51, 255, 51, 0.75)) => 0.75 opacify(rgba(51, 255, 51, 0.75), 0.1) => rgba(51, 255, 51, 0.85) fade-in(rgba(51, 255, 51, 0.75), 0.1) => rgba(51, 255, 51, 0.85) transparentize(rgba(51, 255, 51, 0.75), 0.1) => rgba(51, 255, 51, 0.65) fade-out(rgba(51, 255, 51, 0.75), 0.1) => rgba(51, 255, 51, 0.65) Sass color functions with alpha support! http://nex-3.com/posts/89-powerful-color-manipulation-with-sass
  34. CSS3 ★ Appearance ★ Background Clip ★ Background Origin ★

    Background Size ★ Border Radius ★ Box ★ Box Shadow ★ Box Sizing ★ CSS3 Pie ★ Columns ★ Font Face ★ Gradient ★ Images ★ Inline Block ★ Opacity ★ Shared Utilities ★ Text Shadow ★ Transform ★ Transform (legacy) ★ Transition
  35. @import "icon/*.png" .actions .new +icon-sprite(new) .edit +icon-sprite(edit) .save +icon-sprite(save) .delete

    +icon-sprite(delete) Image sprites .icon-sprite, .actions .new, .actions .edit, .actions .save, .actions .delete { background: url('/images/icon-34fe0604ab.png') no-repeat; } .actions .new { background-position: 0 -64px; } .actions .edit { background-position: 0 -32px; } .actions .save { background-position: 0 -96px; } .actions .delete { background-position: 0 0; } @import "icon/*.png" public/images/icon/new.png public/images/icon/edit.png public/images/icon/save.png public/images/icon/delete.png 1. 2. 3. I like the Sprite in you®
  36. #nav background: image-url("nav_bg.png") repeat-x top center DEVELOPMENT #nav { background:

    url("/images/nav_bg.png") repeat-x top center; } PRODUCTION #nav { background: url("http://assets.example.com/images/nav_bg.png") repeat-x top center; } URL helpers relative paths for development, absolute for production
  37. $ gem install compass-wordpress CRANK OUT A NEW SASS-Y WORDPRESS

    THEME $ compass -r compass-wordpress \ -f wordpress -p thematic \ --sass-dir=sass --css-dir=css \ -s compressed my_awesome_theme AUTOCOMPILE YOUR CHANGES $ compass --watch Compass and WordPress shameless plug
  38. #profile .left.column #date= print_date #address= current_user.address .right.column #email= current_user.email #bio=

    current_user.bio HAML <div id="profile"> <div class="left column"> <div id="date"><%= print_date %></div> <div id="address"><%= current_user.address %></ div> </div> <div class="right column"> <div id="email"><%= current_user.email %></div> <div id="bio"><%= current_user.bio %></div> </div> </div> ERB
  39. charity [ master: ✔ ] 1d ⚡ tree app/assets/ app/assets/javascripts/

    ├── application.js.coffee ├── ie8.js.coffee ├── media.js.coffee ├── mobile.js.coffee ├── pc │ ├── _boot.js.coffee │ ├── models │ │ ├── campaign.js.coffee │ │ ├── campaigns.js.coffee │ │ ├── project.js.coffee │ │ ├── projects.js.coffee │ │ └── scoreboard.js.coffee │ ├── routers │ │ └── discover.js.coffee │ └── views │ ├── calc.js.coffee │ ├── cropper.js.coffee │ ├── data_table.js.coffee │ ├── discover │ │ ├── app.js.coffee │ │ ├── campaigns_panel.js.coffee │ │ ├── map.js.coffee
  40. var foo = function () { } foo = ()

    -> I’d rather write this. JAVASCRIPT COFFEESCRIPT
  41. var button = Titanium.UI.createButton({ title: 'I am a Button', height:

    40, width: 200, top: 10 }); button.addEventListener('click', function(e) { alert("Oooh, that tickles!"); }); JAVASCRIPT
  42. button = Titanium.UI.createButton title: 'I am a Button' height: 40

    width: 200 top: 10 button.addEventListener 'click', (e) -> alert "Oooh, that tickles!" COFFEESCRIPT
  43. for own key, value of query uri += "#{ key

    }=#{ escape(value) }&" COFFEESCRIPT var key, value; var __hasProp = Object.prototype.hasOwnProperty; for (key in query) { if (!__hasProp.call(query, key)) continue; value = query[key]; uri += "" + key + "=" + (escape(value)) + "&"; } JAVASCRIPT
  44. for own key, value of query uri += "#{ key

    }=#{ escape(value) }&" COFFEESCRIPT Comprehensions
  45. for own key, value of query uri += "#{ key

    }=#{ escape(value) }&" COFFEESCRIPT Interpolation
  46. class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor='brag', @scoringFormat='low_net') -> @players =

    {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1 # elsewhere game = new GolfStatus.Models.Game(...) COFFEESCRIPT Simple inheritance pattern
  47. class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor='brag', @scoringFormat='low_net') -> @players =

    {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1 COFFEESCRIPT @
  48. class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor='brag', @scoringFormat='low_net') -> @players =

    {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1 COFFEESCRIPT Default values
  49. class GolfStatus.Models.Game constructor: (@owner, @course, @playingFor='brag', @scoringFormat='low_net') -> @players =

    {} @addPlayer @owner if @owner @green = @course.greens[0] if @course @currentHole = 1 @maxHolePlayed = 1 COFFEESCRIPT More human conditionals