facades 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +24 -0
- data/Rakefile +1 -0
- data/app/helpers/facades_helper.rb +30 -0
- data/facades.gemspec +24 -0
- data/lib/facades/debug/html.rb +6 -0
- data/lib/facades/engine.rb +9 -0
- data/lib/facades/helpers/elements.rb +78 -0
- data/lib/facades/helpers/layout.rb +119 -0
- data/lib/facades/helpers/navigation.rb +130 -0
- data/lib/facades/stylesheets/facades/_layout.scss +2 -0
- data/lib/facades/stylesheets/facades/_reset.scss +84 -0
- data/lib/facades/stylesheets/facades/_util.css.scss +18 -0
- data/lib/facades/stylesheets/facades/layout/_forms.scss +128 -0
- data/lib/facades/stylesheets/facades/layout/_grid.scss +62 -0
- data/lib/facades/stylesheets/facades/typography/_rhythm.scss +15 -0
- data/lib/facades/version.rb +3 -0
- data/lib/facades.rb +33 -0
- data/spec/facades/helpers/elements_spec.rb +86 -0
- data/spec/facades/helpers/layout_helpers_spec.rb +5 -0
- data/spec/facades/helpers/navigation_spec.rb +4 -0
- metadata +96 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Facades
|
2
|
+
|
3
|
+
Facades is a gem designed to assist with front-end development and misc design. It includes a compass plugin / mixins, and various Rails view helpers to help with
|
4
|
+
common development tasks.
|
5
|
+
|
6
|
+
## CSS / SASS
|
7
|
+
|
8
|
+
Facades includes several mixins and includes for setting up a few defaults within your css.
|
9
|
+
|
10
|
+
### Reset
|
11
|
+
A HTML5-friendly reset is included to ensure elements like `aside`, `section` etc are setup properly. It also sets up a few typography defaults using Compass'
|
12
|
+
vertical-rhythm format.
|
13
|
+
|
14
|
+
To configure, assign the variables to `$font-size` and `$line-height`. These will default to 12px / 24px. Vertical-rhythm is defaulted to relative font sizes.
|
15
|
+
|
16
|
+
### Layout
|
17
|
+
Mixins are provided for a fixed grid, forms, and grid debugging. To setup a grid, `@include 'facades/layout/grid'` ( or simply `facades/layout`) and configure the following:
|
18
|
+
|
19
|
+
* `$grid-width` The full width of the container in which your layout resides (default 960px)
|
20
|
+
* `$grid-columns` The number of columns within the grid (default 24)
|
21
|
+
* `$grid-gutter-width` The spacing between each column (default 10px)
|
22
|
+
|
23
|
+
To debug grid alignment, a shortcut to the Compass' grid background is provided. `@include debug-grid;` into your container element to debug.
|
24
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module FacadesHelper
|
2
|
+
|
3
|
+
include Facades::Helpers::Layout
|
4
|
+
include Facades::Helpers::Navigation
|
5
|
+
|
6
|
+
def facade_assets
|
7
|
+
content = if_ie(8) do
|
8
|
+
javascript_include_tag("https://html5shim.googlecode.com/svn/trunk/html5.js")
|
9
|
+
end
|
10
|
+
content.to_s.html_safe
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Render an IE conditional statement. By default conditionals use a less-than-or-equal-to format. Use the `specific`
|
15
|
+
# param to force only that version.
|
16
|
+
#
|
17
|
+
# @param version [Integer] The IE version to target
|
18
|
+
# @param specific [Boolean] optional Target the IE version specificially.
|
19
|
+
#
|
20
|
+
#
|
21
|
+
def if_ie(version, specific = false, &block)
|
22
|
+
content = capture(&block)
|
23
|
+
condition = specific ? "IE #{version}" : "lte IE #{version}"
|
24
|
+
str = "<!--[if #{condition}]>"
|
25
|
+
str << content.html_safe.lstrip
|
26
|
+
str << "<![endif]-->"
|
27
|
+
str.html_safe
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/facades.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "facades/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "facades"
|
7
|
+
s.version = Facades::VERSION
|
8
|
+
s.authors = ["Brent Kirby"]
|
9
|
+
s.email = ["brent@kurbmedia.com"]
|
10
|
+
s.homepage = "https://github.com/kurbmedia/facades"
|
11
|
+
s.summary = %q{Mixins, utilities, and helpers for front-end design/development with Compass / Rails}
|
12
|
+
s.description = %q{Facades includes various helpers, methods, and compass/sass mixins for simplifying frontend development.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "facades"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency('sass', ['~> 3.1'])
|
22
|
+
s.add_dependency('compass', ['>= 0.11'])
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Facades
|
2
|
+
module Helpers
|
3
|
+
##
|
4
|
+
#
|
5
|
+
# Generates misc html elements that aren't included in Rails core, or are custom.
|
6
|
+
#
|
7
|
+
module Elements
|
8
|
+
|
9
|
+
##
|
10
|
+
# Generates a "button" link tag. Simply a convenience method to skip adding 'class="button"' and also adds an +icon+ option
|
11
|
+
# @see Motr::Forms::Builder#button For form related buttons
|
12
|
+
#
|
13
|
+
# @param [String] txt The link text
|
14
|
+
# @param [String] path The link href
|
15
|
+
# @param [Types] Name Description
|
16
|
+
#
|
17
|
+
# @example Create a plain link.button
|
18
|
+
# button_link('Blog', '/blog') #=> <a href="/blog" class="button">Blog</a>
|
19
|
+
# @example Create a link.button with icon
|
20
|
+
# button_link('Blog', '/blog', :icon => 'blog_image.png') #=> <a href="/blog" class="button"><img src="/images/blog_image.png" alt="Blog" /> Blog</a>
|
21
|
+
|
22
|
+
def button_link(txt, path, attrs = {}, incl_span = false)
|
23
|
+
image = attrs.delete(:icon)
|
24
|
+
klasses = (attrs.delete(:class) || "").split(" ")
|
25
|
+
klasses << 'button'
|
26
|
+
klasses = klasses.uniq.compact
|
27
|
+
content = ""
|
28
|
+
content << image_tag(image) unless image.nil?
|
29
|
+
content << (incl_span ? "<span>#{txt}</span>" : txt)
|
30
|
+
link_to content.html_safe, path, attrs.merge(:class => klasses.join(" "))
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
#
|
35
|
+
# Convenience method for outputting all current flash messages. This allows you to avoid
|
36
|
+
# using things like "if flash[:success]" and so on, which is far from DRY
|
37
|
+
#
|
38
|
+
# @param [Hash] attrs Options to modify the html attributes and settings
|
39
|
+
# @option attrs [Symbol] closer Specify HTML to be appended to the message in case you want a "close" button/link. Defaults to "<span>X</span>"
|
40
|
+
# @option attrs [Symbol] wrapper Specify the HTML element which wraps each message. Defaults to :div
|
41
|
+
#
|
42
|
+
# @example Output any available flash messages, appending a "closer" span
|
43
|
+
# In your controller:
|
44
|
+
# flash[:success] = "You did something awesome"
|
45
|
+
# In your view or layout
|
46
|
+
# <%= flash_messages :close => "<span>X</span>" %> #=> <div class="flash_message flash_message_success success">You did something awesome <span>X</span></div>
|
47
|
+
#
|
48
|
+
# @example Output a message without a "close"
|
49
|
+
# <%= flash_messages :close => false %> #=> <div class="flash_message flash_message_success success">You did something awesome</div>
|
50
|
+
#
|
51
|
+
#
|
52
|
+
def flash_messages(attrs = {})
|
53
|
+
|
54
|
+
return if flash.nil? or flash.empty?
|
55
|
+
|
56
|
+
wrapper = attrs.delete(:wrapper) || :div
|
57
|
+
closer = attrs.delete(:closer)
|
58
|
+
unless closer === false
|
59
|
+
closer ||= "<span>X</span>"
|
60
|
+
end
|
61
|
+
klasses = (attrs.delete(:class) || "").split(" ")
|
62
|
+
klasses << "flash_message"
|
63
|
+
content = ""
|
64
|
+
|
65
|
+
flash.each do |key, value|
|
66
|
+
klasses << "flash_message_#{key.to_s.underscore}"
|
67
|
+
msg_attrs = attrs.merge(:class => [key.to_s, klasses].flatten.join(' '))
|
68
|
+
content.concat content_tag(wrapper, "#{value} #{closer}".html_safe, msg_attrs).html_safe
|
69
|
+
end
|
70
|
+
|
71
|
+
content.html_safe
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Facades
|
2
|
+
module Helpers
|
3
|
+
##
|
4
|
+
#
|
5
|
+
# # Convenience helpers generally used in layout files
|
6
|
+
#
|
7
|
+
module Layout
|
8
|
+
|
9
|
+
##
|
10
|
+
#
|
11
|
+
# Allows easy assigning of meta tags from templates
|
12
|
+
# @param [Symbol] name Name of the meta tag (ie: keywords / description)
|
13
|
+
# @param [String] content The content to be used in the meta tag
|
14
|
+
# @return [String] A html meta tag with the name and content attributes set
|
15
|
+
#
|
16
|
+
def meta_tag(name, content = nil)
|
17
|
+
return _retrieve_variable(:"__#{name}") if content.nil?
|
18
|
+
content = tag(:meta, :name => name, :content => content)
|
19
|
+
_create_variable(:"__#{name}", content, false)
|
20
|
+
content
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
#
|
25
|
+
# Creates a page id to be used for identifying a page for CSS/design purposes. If a variable
|
26
|
+
# is defined, it will be used. If not, one will be generated from the current controller/action.
|
27
|
+
#
|
28
|
+
# @param [String] content The string to be used as the page id.
|
29
|
+
# @return [String] The assigned page id
|
30
|
+
# @example Create a page_id and use it in the body tag
|
31
|
+
# <%= page_id('home') %>
|
32
|
+
#
|
33
|
+
# <body id="<%= page_id %>"> #=> <body id="home">
|
34
|
+
#
|
35
|
+
# @example Defaulting page id to controller/action
|
36
|
+
# # IndexController#home
|
37
|
+
# <body id="<%= page_id %>"> #=> <body id="index_home">
|
38
|
+
#
|
39
|
+
#
|
40
|
+
def page_id(content = nil)
|
41
|
+
_create_variable(:__page_id, content, false) and return unless content.nil?
|
42
|
+
return _retrieve_variable(:__page_id) if content_for?(:__page_id)
|
43
|
+
cname = controller.class.to_s.gsub(/controller$/i,'').underscore.split("/").join('_')
|
44
|
+
aname = controller.action_name
|
45
|
+
"#{cname}_#{aname}"
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
#
|
50
|
+
# Convenienve method to create a page title for the <title></title> tag.
|
51
|
+
#
|
52
|
+
# @param [String] content The text for the page title
|
53
|
+
# @return [String] The provided content
|
54
|
+
# @example Set the page title from a view template
|
55
|
+
# <%= page_title('This is my page title') %>
|
56
|
+
#
|
57
|
+
# # In the layout:
|
58
|
+
# <title><%= page_title %></title> #=> <title>This is my page title</title>
|
59
|
+
#
|
60
|
+
def page_title(content = nil)
|
61
|
+
_create_variable(:__page_title, content, false) and return unless content.nil?
|
62
|
+
return _retrieve_variable(:__page_title) if content_for?(:__page_title)
|
63
|
+
return ""
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
#
|
68
|
+
# Convenience method for content_for allowing for single-line variable creation. Also defines a method that can be
|
69
|
+
# re-used within a template.
|
70
|
+
#
|
71
|
+
# @param [Symbol] var_name The name of the variable to create
|
72
|
+
# @param [String] content The content that variable defines
|
73
|
+
# @return [String] An empty string. Use the newly created method from +var_name+ to return the value
|
74
|
+
#
|
75
|
+
# @example Setting a "page_class" variable
|
76
|
+
# <% set_var(:page_class, 'cool') %>
|
77
|
+
# <%= page_class %> #=> 'cool'
|
78
|
+
#
|
79
|
+
#
|
80
|
+
def set_var(var_name, content)
|
81
|
+
_create_variable("#{var_name}", content) and return ''
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
#
|
86
|
+
# Configures a "robots" meta tag based on the rails environment. In environments other than 'production'
|
87
|
+
# it sets the value to "noindex, nofollow" for each page that uses the layout in which it is called. This
|
88
|
+
# helps prevent spiders from crawling / indexing content when used on staging sites.
|
89
|
+
#
|
90
|
+
# @return [String] A html meta tag for "robots" with the appropriate content attribute set
|
91
|
+
#
|
92
|
+
def robot_meta_tag
|
93
|
+
tag(:meta, :name => 'robots', :content => (Rails.env.eql?('production') ? 'index, follow' : 'noindex, nofollow'))
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def _create_variable(var, content, create_method = true) #:nodoc:
|
99
|
+
content_for(var.to_sym) do
|
100
|
+
content
|
101
|
+
end
|
102
|
+
return '' unless create_method
|
103
|
+
class_eval <<-MAKE_VAR, __FILE__, __LINE__ + 1
|
104
|
+
def #{var}
|
105
|
+
content_for(:#{var})
|
106
|
+
end
|
107
|
+
public :#{var}
|
108
|
+
MAKE_VAR
|
109
|
+
end
|
110
|
+
|
111
|
+
def _retrieve_variable(var) #:nodoc:
|
112
|
+
(content_for?(var.to_sym) ? content_for(var.to_sym) : "")
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Facades
|
2
|
+
module Helpers
|
3
|
+
##
|
4
|
+
#
|
5
|
+
# Convenience helpers for building navigation lists, and defining 'on' states.
|
6
|
+
#
|
7
|
+
module Navigation
|
8
|
+
|
9
|
+
##
|
10
|
+
#
|
11
|
+
# Creates a link wrapped in a list item, to be used within a list-based navigation.
|
12
|
+
#
|
13
|
+
# @param [String] text The text used within the link
|
14
|
+
# @param [String] path The url used as the link's +href+ attribute
|
15
|
+
# @param [Hash] attrs Hash of attributes to be applied to the link. This format is the same as Rail's +link_to+ helper
|
16
|
+
# @option attrs [String] :active_class The class to use if this link is 'active'. Defaults to "on"
|
17
|
+
# @option attrs [Proc] :proc A callback which, when called, determines the active state of the link
|
18
|
+
# @option attrs [Regex] :matcher A regular expression to be matched against +path+
|
19
|
+
# @param [Symbol] wrapper The html tag to be used as the wrapper. Defaults to +:li+
|
20
|
+
#
|
21
|
+
# @example Create a list item link to any page
|
22
|
+
# nav_link('Home Page', '/home') #=> <li><a href="/home">Home Page</a>
|
23
|
+
#
|
24
|
+
# @example 'Active state' functionality for the current page
|
25
|
+
# nav_link('Current Page', '/current_url') #=> <li class="on"><a href="/current_url" class="on">Current Page</a></li>
|
26
|
+
#
|
27
|
+
def nav_link(text, path, attrs = {}, wrapper = :li, &block)
|
28
|
+
|
29
|
+
if block_given?
|
30
|
+
return sub_nav_link(text, path, attrs, wrapper, :ol, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
link_attrs = update_link_attrs(path, attrs)
|
34
|
+
wrapper_attrs = link_attrs.delete(:wrapper)
|
35
|
+
child_link = link_to(text, path, link_attrs)
|
36
|
+
wrapper === false ? child_link : content_tag(wrapper, child_link, wrapper_attrs)
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def sub_nav_link(text, path, attrs = {}, wrapper = :li, container = :ol, &block)
|
41
|
+
wrapper_attrs = attrs.delete(:wrapper)
|
42
|
+
link_attrs = update_link_attrs(path, attrs.merge(:wrapper => (attrs.delete(:item) || {}) ))
|
43
|
+
parent_link = nav_link_to(text, path, attrs, false)
|
44
|
+
child_links = content_tag(container, capture(&block), wrapper_attrs)
|
45
|
+
content_tag(container) do
|
46
|
+
content_tag(wrapper, (parent_link << child_links), wrapper_attrs)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
private :sub_nav_link
|
50
|
+
|
51
|
+
##
|
52
|
+
#
|
53
|
+
# Creates a navigational list format, including a parent list / wrapper. Useful for nested list navigation
|
54
|
+
# @param [String] text The text used within the link
|
55
|
+
# @param [String] path The url used as the link's +href+ attribute
|
56
|
+
# @param [Hash] attrs Hash of attributes to be applied to the link. This format is the same as Rail's +link_to+ helper
|
57
|
+
# @option attrs [String] :active_class The class to use if this link is 'active'. Defaults to "on"
|
58
|
+
# @option attrs [Proc] :proc A callback which, when called, determines the active state of the link
|
59
|
+
# @option attrs [Regex] :matcher A regular expression to be matched against +path+
|
60
|
+
# @param [Symbol] wrapper The html tag to be used as the wrapper. Defaults to +:li+
|
61
|
+
# @param [Symbol] container The element that will be used as a container for the nested list
|
62
|
+
# @param [Block] &block A block containing the content of the nested items
|
63
|
+
#
|
64
|
+
# @example Create a nested list navigation
|
65
|
+
# nav do
|
66
|
+
# nav_link('About Page', '/about')
|
67
|
+
# end
|
68
|
+
# @example
|
69
|
+
# <ol>
|
70
|
+
# <li><a href="/home">Home Page</a>
|
71
|
+
# <ol>
|
72
|
+
# <li><a href="/about">Sub Page</a></li>
|
73
|
+
# </ol>
|
74
|
+
# </li>
|
75
|
+
# </ol>
|
76
|
+
#
|
77
|
+
def nav(container = :ol, html_attrs = {}, &block)
|
78
|
+
|
79
|
+
wrapper_attrs = html_attrs.delete(:wrapper) || {}
|
80
|
+
|
81
|
+
if Facades.enable_html5
|
82
|
+
content_tag(:nav, html_attrs) do
|
83
|
+
content_tag(container, capture(&block), wrapper_attrs)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
content_tag(container, capture(&block), html_attrs)
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# @private
|
94
|
+
def update_link_attrs(path, attrs)
|
95
|
+
|
96
|
+
proc = attrs.delete(:proc) || false
|
97
|
+
regex = attrs.delete(:matcher) || false
|
98
|
+
klasses = attrs.delete(:class).try(:split, ' ')
|
99
|
+
on_class = attrs.delete(:active_class) || "on"
|
100
|
+
wrapper_attrs = attrs.delete(:wrapper) || {}
|
101
|
+
wklasses = wrapper_attrs[:class].try(:split, ' ')
|
102
|
+
|
103
|
+
klasses ||= []
|
104
|
+
wklasses ||= []
|
105
|
+
|
106
|
+
matcher = (proc || regex || request.path)
|
107
|
+
|
108
|
+
active = case matcher
|
109
|
+
when Proc then proc.call(path)
|
110
|
+
when Regexp then request.path.match(regex)
|
111
|
+
when String then (request.path == path || request.path.match(/#{path}\/\w/im))
|
112
|
+
else raise Motr::Errors::InvalidOptions.new('Proc, Regexp or String required... passed #{matcher.class}.')
|
113
|
+
end
|
114
|
+
|
115
|
+
if active
|
116
|
+
klasses << on_class
|
117
|
+
wklasses << on_class
|
118
|
+
end
|
119
|
+
|
120
|
+
attrs.merge!(:class => klasses.join(" ")) unless klasses.compact.empty?
|
121
|
+
wrapper_attrs.merge!(:class => wklasses.join(" ")) unless wklasses.compact.empty?
|
122
|
+
|
123
|
+
attrs.merge!(:wrapper => wrapper_attrs)
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
@import 'facades/typography/rhythm';
|
2
|
+
|
3
|
+
//
|
4
|
+
// Establishes a default baseline for vertical rhythm
|
5
|
+
// CSS Reset from html5doctor.com
|
6
|
+
//
|
7
|
+
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
|
8
|
+
small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td,
|
9
|
+
article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video {
|
10
|
+
margin:0; padding:0; border:0; outline:0; vertical-align:baseline; background:transparent;
|
11
|
+
}
|
12
|
+
body { line-height:1; }
|
13
|
+
article,aside,canvas,details,figcaption,figure,footer,header,hgroup,menu,nav,section,summary{ display:block; }
|
14
|
+
nav ul { list-style:none; }
|
15
|
+
blockquote, q {
|
16
|
+
quotes:none;
|
17
|
+
&:before, &:after{
|
18
|
+
content:'';
|
19
|
+
content:none;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
a{ margin:0; padding:0; font-size:100%; vertical-align:baseline; background:transparent; }
|
24
|
+
ins { background-color:#ff9; color:#000; text-decoration:none; }
|
25
|
+
mark { background-color:#ff9; color:#000; font-style:italic; font-weight:bold; }
|
26
|
+
del { text-decoration: line-through; }
|
27
|
+
abbr[title], dfn[title] { border-bottom:1px dotted #000; cursor:help; }
|
28
|
+
table { border-collapse:collapse; border-spacing:0; }
|
29
|
+
hr { display:block; height:1px; border:0; border-top:1px solid #cccccc; margin:1em 0; padding:0; }
|
30
|
+
input, select { vertical-align:middle; }
|
31
|
+
|
32
|
+
$base-font-size: $font-size;
|
33
|
+
$base-line-height: $line-height;
|
34
|
+
|
35
|
+
// Establish a baseline by default.
|
36
|
+
@include establish-baseline($font-size);
|
37
|
+
body{
|
38
|
+
font-size-adjust:none;
|
39
|
+
@include normal-text;
|
40
|
+
}
|
41
|
+
img{ margin:0; }
|
42
|
+
|
43
|
+
// Establish reasonable heading and font sizes, with line-heights based on vertical rhythm.
|
44
|
+
|
45
|
+
h1,h2,h3,h4,h5,h6{ font-weight:normal; }
|
46
|
+
h1{ @include font-size(32px, 2); }
|
47
|
+
h2{ @include font-size(28px, 2); }
|
48
|
+
h3{ @include font-size(26px, 2); }
|
49
|
+
h4{ @include font-size(22px, 2); }
|
50
|
+
h5{ @include font-size(16px, 1); }
|
51
|
+
h6{ @include font-size(11px, 1); }
|
52
|
+
p{ @include font-size($font-size, 1); }
|
53
|
+
|
54
|
+
a{ text-decoration:underline; color:$link-color;
|
55
|
+
&:hover{ color:$link-hover-color; }
|
56
|
+
&:focus{ color:$link-focus-color; }
|
57
|
+
&:active{ color:$link-active-color; }
|
58
|
+
&:visited{ color:$link-visited-color; }
|
59
|
+
}
|
60
|
+
|
61
|
+
blockquote{ font-style:italic; }
|
62
|
+
strong, dfn{ font-weight: bold; }
|
63
|
+
em, dfn{ font-style: italic; }
|
64
|
+
sup, sub{ line-height: 0; }
|
65
|
+
abbr, acronym{ border-bottom: 1px dotted lighten($font-color, 10%); }
|
66
|
+
address{ margin: 0 0 1.5em; font-style: italic; }
|
67
|
+
pre{ margin: 1.5em 0; white-space:pre; }
|
68
|
+
pre, code, tt{ @include fixed-width-text; }
|
69
|
+
li ul, li ol{ margin: 0; }
|
70
|
+
ul, ol{ margin: 0 1.5em 1.5em 0; padding-left: 1.5em; }
|
71
|
+
ul{ list-style-type: $unordered-list-type; }
|
72
|
+
ol{ list-style-type: $ordered-list-type; }
|
73
|
+
dl{ margin: 0 0 1.5em 0;
|
74
|
+
dt{ font-weight: bold; }
|
75
|
+
}
|
76
|
+
dd{ margin-left: 1.5em; }
|
77
|
+
table{ margin-bottom: 1.4em; width: 100%;
|
78
|
+
th{ font-weight: bold; }
|
79
|
+
thead th{ background: $table-header-color; }
|
80
|
+
th,td,caption{ padding: 4px 10px 4px 5px; }
|
81
|
+
table.striped tr:nth-child(even) td,
|
82
|
+
table tr.even td{ background:$table-stripe-color; }
|
83
|
+
}
|
84
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
// From thoughtbot/bourbon
|
2
|
+
@mixin position ($position: relative, $coordinates: 0 0 0 0) {
|
3
|
+
@if type-of($position) == list {
|
4
|
+
$coordinates: $position;
|
5
|
+
$position: relative;
|
6
|
+
}
|
7
|
+
|
8
|
+
$top: nth($coordinates, 1);
|
9
|
+
$right: nth($coordinates, 2);
|
10
|
+
$bottom: nth($coordinates, 3);
|
11
|
+
$left: nth($coordinates, 4);
|
12
|
+
position: $position;
|
13
|
+
|
14
|
+
@if not(unitless($top)){ top: $top; }
|
15
|
+
@if not(unitless($right)) { right: $right; }
|
16
|
+
@if not(unitless($bottom)) { bottom: $bottom; }
|
17
|
+
@if not(unitless($left)) { left: $left; }
|
18
|
+
}
|
@@ -0,0 +1,128 @@
|
|
1
|
+
// Default border radius used on inputs
|
2
|
+
$input-border-radius:2px !default;
|
3
|
+
// Default font size for form fields... slightly smaller than body font size
|
4
|
+
$input-font-size: .95em !default;
|
5
|
+
// Default input border color
|
6
|
+
$unfocused-border-color:#bbbbbb !default;
|
7
|
+
// Input border color when focused
|
8
|
+
$focus-border-color: #666666 !default;
|
9
|
+
// Class used on fields which are invalid
|
10
|
+
$form-error-class: 'field-with-error' !default;
|
11
|
+
// Selector representing the error class and element used to display error messages
|
12
|
+
$form-error-message-selector: 'span.error-for-field' !default;
|
13
|
+
// Text color for field hints
|
14
|
+
$form-hint-color: #ccc;
|
15
|
+
// Selector for field hints
|
16
|
+
$form-hint-selector: 'span.hint';
|
17
|
+
// Default fieldset border color
|
18
|
+
$fieldset-border-color: #ccc !default;
|
19
|
+
// Default error text color
|
20
|
+
$error-color: #bd132a !default;
|
21
|
+
// Default error background color, applies to inputs / selects / textareas
|
22
|
+
$error-bg-color: #fde0e4 !default;
|
23
|
+
// Default error border color, applies to inputs / selects / textareas
|
24
|
+
$error-border-color: #E41D38 !default;
|
25
|
+
|
26
|
+
// Mixin for styling select boxes
|
27
|
+
@mixin form-select( $font-size: $input-font-size, $normal-border: $unfocused-border-color, $focus-border: $focus-border-color, $border-radius: $input-border-radius ){
|
28
|
+
@include form-field($font-size, $input-size, $normal-border, $focus-border, $border-radius);
|
29
|
+
border-style:solid;
|
30
|
+
&:focus{ outline:none; }
|
31
|
+
&[multiple=multiple]{ border-color:$unfocused-border-color; }
|
32
|
+
}
|
33
|
+
|
34
|
+
// Mixin for styling textareas
|
35
|
+
@mixin form-textarea( $font-size: $input-font-size, $normal-border: $unfocused-border-color, $focus-border: $focus-border-color, $border-radius: $input-border-radius ){
|
36
|
+
@include form-field($font-size, $input-size, $normal-border, $focus-border, $border-radius);
|
37
|
+
margin:0.5em; padding:5px;
|
38
|
+
}
|
39
|
+
|
40
|
+
// Default input styling
|
41
|
+
@mixin form-input( $font-size: $input-font-size, $normal-border: $unfocused-border-color, $focus-border: $focus-border-color, $border-radius: $input-border-radius ){
|
42
|
+
&.text,
|
43
|
+
&[type=text],
|
44
|
+
&[type=password],
|
45
|
+
&[type=email]{
|
46
|
+
@include form-field($font-size, $input-size, $normal-border, $focus-border, $border-radius); padding:.65em;
|
47
|
+
}
|
48
|
+
&[type=checkbox],
|
49
|
+
&[type=radio]{
|
50
|
+
@include inline-block; margin-right:1em; vertical-align:baseline; width:auto;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
// Global base styles for all input types
|
55
|
+
@mixin form-field( $font-size: $input-font-size, $normal-border: $unfocused-border-color, $focus-border: $focus-border-color, $border-radius: $input-border-radius ){
|
56
|
+
@include border-radius($border-radius);
|
57
|
+
font-size:$font-size;
|
58
|
+
border-color:$normal-border;
|
59
|
+
&:focus{ outline:none; border-color:$focus-border; }
|
60
|
+
}
|
61
|
+
|
62
|
+
// Mixin for displaying errors and error messages on fields.
|
63
|
+
@mixin form-errors( $color:$error-color, $border-color:$error-border-color, $bg-color:$error-bg-color ){
|
64
|
+
&.#{$form-error-class}{
|
65
|
+
input[type=text],
|
66
|
+
input[type=password],
|
67
|
+
input[type=email],
|
68
|
+
textarea{
|
69
|
+
border:1px solid $border-color;
|
70
|
+
background:$bg-color;
|
71
|
+
}
|
72
|
+
label{ color:$color; }
|
73
|
+
#{$form-hint-selector}{ display:none; }
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
// Mixin for displaying form hints
|
78
|
+
@mixin form-field-hint( $color: $form-hint-color ){
|
79
|
+
font-size:.95em; line-height:.95em; font-weight:normal; color:$color; display:block;
|
80
|
+
}
|
81
|
+
|
82
|
+
// Mixin for styling field error messages
|
83
|
+
@mixin form-error-message($color: $error-color){
|
84
|
+
font-size:.95em; line-height:.95em; color:$error-color; display:block;
|
85
|
+
}
|
86
|
+
|
87
|
+
// Creates a column based list of fields within a form. Forms elements should be marked up using ordered lists for semantic value.
|
88
|
+
@mixin form-split-field-list{
|
89
|
+
display:block; clear:both; margin:-.5em 0px; @include pie-clearfix;
|
90
|
+
li{ float:left; margin:0 1em 0 0; vertical-align:middle;
|
91
|
+
label,
|
92
|
+
input{
|
93
|
+
&[type=text],
|
94
|
+
&[type=password],
|
95
|
+
&[type=email]{ display:block; }
|
96
|
+
}
|
97
|
+
select{ margin:.75em 0px; }
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
// Creates a single column list of fields within a form. Form elements should be marked up using ordered lists for semantic value.
|
102
|
+
@mixin form-field-list{
|
103
|
+
ol{ list-style-type:none; margin:0px; padding:0px; padding-right:10px;
|
104
|
+
li{ padding:.5em 0px;
|
105
|
+
&.clear{ clear:both; }
|
106
|
+
&.buttons{ clear:both; padding:.25em 0px 0px 0px; }
|
107
|
+
&.inline label{ @include inline-block; }
|
108
|
+
&.multifield{
|
109
|
+
input, select{ @include inline-block; }
|
110
|
+
}
|
111
|
+
ol{ @include form-split-field-list; }
|
112
|
+
@include form-errors;
|
113
|
+
|
114
|
+
#{$form-hint-selector}{ @include form-hint; }
|
115
|
+
#{$form-error-message-selector}{ @include form-error-messages( $color ); }
|
116
|
+
|
117
|
+
}
|
118
|
+
label{ display:block; }
|
119
|
+
@include form-select; @include form-input; @include form-textarea;
|
120
|
+
}
|
121
|
+
ol.inline li.label{ @include inline-block; }
|
122
|
+
label abbr{ outline:none; border:none; color:red; }
|
123
|
+
label{
|
124
|
+
font-size:12px;
|
125
|
+
height:20px;
|
126
|
+
}
|
127
|
+
fieldset{ border:none; }
|
128
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
// Fixed grid system based on a merge of Blueprint and 960gs.
|
2
|
+
$grid-gutter-width: 10px !default;
|
3
|
+
$grid-width: 960px !default;
|
4
|
+
$grid-columns: 24 !default;
|
5
|
+
$grid-column-width: $grid-width / $grid-columns * 1 - $grid-gutter-width;
|
6
|
+
|
7
|
+
@mixin container{
|
8
|
+
margin-left: auto;
|
9
|
+
margin-right: auto;
|
10
|
+
width: $grid-width;
|
11
|
+
@include pie-clearfix;
|
12
|
+
}
|
13
|
+
|
14
|
+
@function span($n){
|
15
|
+
@return $grid-width / $grid-columns * $n - $grid-gutter-width;
|
16
|
+
}
|
17
|
+
|
18
|
+
@mixin column-base($gutter: $gutter-width){
|
19
|
+
display: inline; float: left;
|
20
|
+
margin-left: $gutter / 2;
|
21
|
+
margin-right: $gutter / 2;
|
22
|
+
}
|
23
|
+
|
24
|
+
@mixin column($n, $cols: $grid-columns, $gutter: $grid-gutter-width){
|
25
|
+
@include column-base($gutter);
|
26
|
+
width:span($n);
|
27
|
+
}
|
28
|
+
|
29
|
+
@mixin first{ margin-left:0; }
|
30
|
+
@mixin last{ margin-right:0; }
|
31
|
+
|
32
|
+
@mixin prefix($n, $cols: $grid-columns){
|
33
|
+
padding-left: $grid-width / $cols * $n;
|
34
|
+
}
|
35
|
+
|
36
|
+
@mixin suffix($n, $cols: $grid-columns){
|
37
|
+
padding-right: $grid-width / $cols * $n;
|
38
|
+
}
|
39
|
+
|
40
|
+
@mixin push($n){
|
41
|
+
position:relative;
|
42
|
+
left: ($grid-width / $cols) * $n;
|
43
|
+
}
|
44
|
+
|
45
|
+
@mixin pull($n){
|
46
|
+
position:relative;
|
47
|
+
right: -($grid-width / $cols) * $n;
|
48
|
+
}
|
49
|
+
|
50
|
+
@import 'compass/layout/grid-background';
|
51
|
+
$grid-background-column-color: #eef2f9;
|
52
|
+
$grid-background-baseline-color: rgba(0,0,0,0.15);
|
53
|
+
$grid-background-gutter-color: #fff;
|
54
|
+
$grid-background-total-columns: $grid-columns;
|
55
|
+
$grid-background-column-width: $grid-column-width;
|
56
|
+
$grid-background-gutter-width: $grid-gutter-width;
|
57
|
+
$grid-background-baseline-height: #{($line-height / $font-size)}em;
|
58
|
+
|
59
|
+
|
60
|
+
@mixin debug-grid{
|
61
|
+
@include grid-background;
|
62
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
@import "compass/typography/vertical_rhythm";
|
2
|
+
@import "compass/utilities/general/clearfix";
|
3
|
+
|
4
|
+
@mixin normal-text { font-family: $font-family; color: $font-color; }
|
5
|
+
@mixin fixed-width-text { font: 1em $fixed-font-family; line-height: 1.5; }
|
6
|
+
|
7
|
+
// Shorthand overrides for Compass' adjust-font-size/leading-to
|
8
|
+
// because well.. they are freakin long.
|
9
|
+
//
|
10
|
+
@mixin font-size($size, $lines){
|
11
|
+
@include adjust-font-size-to($size, $lines);
|
12
|
+
}
|
13
|
+
@mixin leading($size, $lines){
|
14
|
+
@include adjust-leading-to($size, $lines);
|
15
|
+
}
|
data/lib/facades.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'facades/version'
|
3
|
+
|
4
|
+
module Facades
|
5
|
+
|
6
|
+
module Debug
|
7
|
+
autoload :Html, 'facades/debug/html'
|
8
|
+
end
|
9
|
+
|
10
|
+
module Helpers
|
11
|
+
autoload :Layout, 'facades/helpers/layout'
|
12
|
+
autoload :Navigation, 'facades/helpers/navigation'
|
13
|
+
autoload :Elements, 'facades/helpers/elements'
|
14
|
+
end
|
15
|
+
|
16
|
+
mattr_accessor :enable_html5
|
17
|
+
mattr_accessor :debug_html
|
18
|
+
|
19
|
+
def setup(&block)
|
20
|
+
yield self
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
Facades.enable_html5 = true
|
26
|
+
Facades.debug_html = true
|
27
|
+
|
28
|
+
require 'compass'
|
29
|
+
Compass::Frameworks.register('facades',
|
30
|
+
:stylesheets_directory => File.join(File.dirname(__FILE__), 'facades/stylesheets'),
|
31
|
+
:templates_directory => File.join(File.dirname(__FILE__), 'facades/templates'))
|
32
|
+
|
33
|
+
require 'facades/engine' if defined?(Rails)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Facades::Helpers::Elements, :type => :helper do
|
4
|
+
|
5
|
+
describe '#button_link' do
|
6
|
+
|
7
|
+
subject{ button_link("home", "/", attrs).to_html }
|
8
|
+
let(:attrs){ {} }
|
9
|
+
|
10
|
+
it { should have_selector('a.button') }
|
11
|
+
|
12
|
+
context 'when passing classes' do
|
13
|
+
let(:attrs){ { :class => 'test_class' } }
|
14
|
+
|
15
|
+
it { should have_selector('a.test_class') }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when providing an icon' do
|
19
|
+
|
20
|
+
let(:attrs) do
|
21
|
+
{ icon: 'sample.png' }
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'adds an image to the link' do
|
25
|
+
subject.should have_selector('img')
|
26
|
+
end
|
27
|
+
it 'should use the icon attribute as the image' do
|
28
|
+
subject.first('img')[:src].should match "sample.png"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#flash_messages' do
|
35
|
+
|
36
|
+
let!(:flash) do
|
37
|
+
{ success: 'test flash message' }
|
38
|
+
end
|
39
|
+
subject{ flash_messages(attrs).to_html }
|
40
|
+
|
41
|
+
let(:attrs){ {} }
|
42
|
+
|
43
|
+
context 'when rendering normally' do
|
44
|
+
|
45
|
+
it 'wraps the content in a div.flash_message' do
|
46
|
+
should have_selector('div.flash_message')
|
47
|
+
end
|
48
|
+
it 'should have a span closer' do
|
49
|
+
subject.first('div').should have_selector('span')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'adds the flash key as a html class' do
|
53
|
+
should have_selector("div.success")
|
54
|
+
end
|
55
|
+
it 'adds :key_flash_message as a html class' do
|
56
|
+
should have_selector("div.flash_message_success")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when passed false to :closer' do
|
61
|
+
|
62
|
+
let(:attrs) do
|
63
|
+
{ closer: false }
|
64
|
+
end
|
65
|
+
it 'should not add a closer span' do
|
66
|
+
subject.first('div').should_not have_selector('span')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when span is passed to :wrapper' do
|
71
|
+
|
72
|
+
let(:attrs) do
|
73
|
+
{ wrapper: :span }
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should not use a div wrapper' do
|
77
|
+
should_not have_selector('div')
|
78
|
+
end
|
79
|
+
it 'should have a span wrapper' do
|
80
|
+
should have_selector('span.flash_message')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: facades
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Brent Kirby
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-07-30 00:00:00.000000000 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sass
|
17
|
+
requirement: &70302667237140 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3.1'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70302667237140
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: compass
|
28
|
+
requirement: &70302667236100 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.11'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70302667236100
|
37
|
+
description: Facades includes various helpers, methods, and compass/sass mixins for
|
38
|
+
simplifying frontend development.
|
39
|
+
email:
|
40
|
+
- brent@kurbmedia.com
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- Gemfile
|
47
|
+
- README.md
|
48
|
+
- Rakefile
|
49
|
+
- app/helpers/facades_helper.rb
|
50
|
+
- facades.gemspec
|
51
|
+
- lib/facades.rb
|
52
|
+
- lib/facades/debug/html.rb
|
53
|
+
- lib/facades/engine.rb
|
54
|
+
- lib/facades/helpers/elements.rb
|
55
|
+
- lib/facades/helpers/layout.rb
|
56
|
+
- lib/facades/helpers/navigation.rb
|
57
|
+
- lib/facades/stylesheets/facades/_layout.scss
|
58
|
+
- lib/facades/stylesheets/facades/_reset.scss
|
59
|
+
- lib/facades/stylesheets/facades/_util.css.scss
|
60
|
+
- lib/facades/stylesheets/facades/layout/_forms.scss
|
61
|
+
- lib/facades/stylesheets/facades/layout/_grid.scss
|
62
|
+
- lib/facades/stylesheets/facades/typography/_rhythm.scss
|
63
|
+
- lib/facades/version.rb
|
64
|
+
- spec/facades/helpers/elements_spec.rb
|
65
|
+
- spec/facades/helpers/layout_helpers_spec.rb
|
66
|
+
- spec/facades/helpers/navigation_spec.rb
|
67
|
+
has_rdoc: true
|
68
|
+
homepage: https://github.com/kurbmedia/facades
|
69
|
+
licenses: []
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project: facades
|
88
|
+
rubygems_version: 1.6.2
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Mixins, utilities, and helpers for front-end design/development with Compass
|
92
|
+
/ Rails
|
93
|
+
test_files:
|
94
|
+
- spec/facades/helpers/elements_spec.rb
|
95
|
+
- spec/facades/helpers/layout_helpers_spec.rb
|
96
|
+
- spec/facades/helpers/navigation_spec.rb
|