big_band 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +27 -0
- data/README.rdoc +303 -0
- data/README.rdoc.erb +39 -0
- data/Rakefile +129 -0
- data/big_band.gemspec +29 -0
- data/example/example.rb +13 -0
- data/example/views/index.haml +8 -0
- data/example/views/layout.haml +2 -0
- data/example/views/stylesheets/_base.sass +1 -0
- data/example/views/stylesheets/screen.sass +12 -0
- data/lib/big_band/advanced_routes.rb +184 -0
- data/lib/big_band/basic_extensions.rb +176 -0
- data/lib/big_band/compass/big_band.rb +4 -0
- data/lib/big_band/compass/stylesheets/_big_band.sass +1 -0
- data/lib/big_band/compass/stylesheets/big_band/_blueprint.sass +1 -0
- data/lib/big_band/compass/stylesheets/big_band/_utilities.sass +6 -0
- data/lib/big_band/compass/stylesheets/big_band/blueprint/_html5.sass +4 -0
- data/lib/big_band/compass/stylesheets/big_band/layouts/_inspector.sass +103 -0
- data/lib/big_band/compass/stylesheets/big_band/utilities/_border_radius.sass +27 -0
- data/lib/big_band/compass/stylesheets/big_band/utilities/_css3_prefix.sass +14 -0
- data/lib/big_band/compass/stylesheets/big_band/utilities/_fancy_buttons.sass +62 -0
- data/lib/big_band/compass/stylesheets/big_band/utilities/_html5.sass +3 -0
- data/lib/big_band/compass.rb +94 -0
- data/lib/big_band/files/overlay-button.png +0 -0
- data/lib/big_band/integration/bacon.rb +10 -0
- data/lib/big_band/integration/monk.rb +26 -0
- data/lib/big_band/integration/rake.rb +60 -0
- data/lib/big_band/integration/rspec.rb +11 -0
- data/lib/big_band/integration/test/spec.rb +2 -0
- data/lib/big_band/integration/test/unit.rb +2 -0
- data/lib/big_band/integration/test.rb +42 -0
- data/lib/big_band/integration/test_spec.rb +8 -0
- data/lib/big_band/integration/test_unit.rb +10 -0
- data/lib/big_band/integration/yard.rb +104 -0
- data/lib/big_band/integration.rb +42 -0
- data/lib/big_band/more_helpers.rb +50 -0
- data/lib/big_band/more_server/rainbows.rb +13 -0
- data/lib/big_band/more_server/unicorn.rb +28 -0
- data/lib/big_band/more_server.rb +14 -0
- data/lib/big_band/reloader.rb +113 -0
- data/lib/big_band/sass.rb +28 -0
- data/lib/big_band/version.rb +3 -0
- data/lib/big_band/web_inspector.rb +178 -0
- data/lib/big_band.rb +239 -0
- data/lib/big_bang.rb +6 -0
- data/lib/yard-sinatra.rb +2 -0
- data/spec/big_band/advanced_routes_spec.rb +70 -0
- data/spec/big_band/basic_extensions_spec.rb +39 -0
- data/spec/big_band/more_server_spec.rb +7 -0
- data/spec/big_band/sass_spec.rb +21 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +4 -0
- data/yard-sinatra.gemspec +24 -0
- metadata +167 -0
@@ -0,0 +1,184 @@
|
|
1
|
+
require "sinatra/base"
|
2
|
+
|
3
|
+
class BigBand < Sinatra::Base
|
4
|
+
|
5
|
+
# AdvancedRoutes makes routes first class objects in Sinatra:
|
6
|
+
#
|
7
|
+
# require "sinatra"
|
8
|
+
# require "big_band"
|
9
|
+
#
|
10
|
+
# admin_route = get "/admin" do
|
11
|
+
# administrate_stuff
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# before do
|
15
|
+
# # Let's deactivate the route if we have no password file.
|
16
|
+
# if File.exists? "admin_password"
|
17
|
+
# admin_route.activate
|
18
|
+
# else
|
19
|
+
# admin_route.deactivate
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# first_route = get "/:name" do
|
24
|
+
# # stuff
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# other_route = get "/foo_:name" do
|
28
|
+
# # other stuff
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# # Unfortunatly first_route will catch all the requests other_route would
|
32
|
+
# # have gotten, since it has been defined first. But wait, we can fix this!
|
33
|
+
# other_route.promote
|
34
|
+
module AdvancedRoutes
|
35
|
+
|
36
|
+
module ArrayMethods
|
37
|
+
::Array.send :include, self
|
38
|
+
|
39
|
+
def to_route(verb, args = {})
|
40
|
+
dup.to_route! verb, args
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_route!(verb, args = {})
|
44
|
+
extend BigBand::AdvancedRoutes::Route
|
45
|
+
self.verb = verb
|
46
|
+
args.each do |key, value|
|
47
|
+
send "#{key}=", value
|
48
|
+
end
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def signature
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
module Route
|
59
|
+
|
60
|
+
attr_accessor :app, :verb, :file, :line, :path
|
61
|
+
|
62
|
+
def pattern; self[0]; end
|
63
|
+
def keys; self[1]; end
|
64
|
+
def conditions; self[2]; end
|
65
|
+
def block; self[3]; end
|
66
|
+
alias to_proc block
|
67
|
+
|
68
|
+
def pattern=(value); self[0] = value; end
|
69
|
+
def keys=(value); self[1] = value; end
|
70
|
+
def conditions=(value); self[2] = value; end
|
71
|
+
def block=(value); self[3] = value; end
|
72
|
+
|
73
|
+
def signature
|
74
|
+
[pattern, keys, conditions, block]
|
75
|
+
end
|
76
|
+
|
77
|
+
def active?
|
78
|
+
app.routes[verb].include? self
|
79
|
+
end
|
80
|
+
|
81
|
+
def activate(at_top = false)
|
82
|
+
also_change.each { |r| r.activate }
|
83
|
+
return if active?
|
84
|
+
meth = at_top ? :unshift : :push
|
85
|
+
(app.routes[verb] ||= []).send(meth, self)
|
86
|
+
invoke_hook :route_added, verb, path, block
|
87
|
+
invoke_hook :advanced_root_activated, self
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
def deactivate
|
92
|
+
also_change.each { |r| r.deactivate }
|
93
|
+
return unless active?
|
94
|
+
(app.routes[verb] ||= []).delete(signature)
|
95
|
+
invoke_hook :route_removed, verb, path, block
|
96
|
+
invoke_hook :advanced_root_deactivated, self
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def promote(upwards = true)
|
101
|
+
also_change.each { |r| r.promote(upwards) }
|
102
|
+
deactivate
|
103
|
+
activate(upwards)
|
104
|
+
end
|
105
|
+
|
106
|
+
def file?
|
107
|
+
!!@file
|
108
|
+
end
|
109
|
+
|
110
|
+
def inspect
|
111
|
+
"#<BigBand::AdvancedRoutes::Route #{ivar_inspect.join ", "}>"
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_route(verb, args = {})
|
115
|
+
args = args.dup
|
116
|
+
[:app, :verb, :file, :line, :path].each { |key| args[key] ||= send(key) }
|
117
|
+
super(verb, args)
|
118
|
+
end
|
119
|
+
|
120
|
+
def also_change(*other_routes)
|
121
|
+
(@also_change ||= []).push(*other_routes)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def ivar_inspect
|
127
|
+
[:signature, :verb, :app, :file, :line].map do |var|
|
128
|
+
value = send(var)
|
129
|
+
"@#{var}=#{value.inspect}" unless value.nil?
|
130
|
+
end.compact
|
131
|
+
end
|
132
|
+
|
133
|
+
def invoke_hook(*args)
|
134
|
+
app.send(:invoke_hook, *args)
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
module ClassMethods
|
140
|
+
|
141
|
+
def get(path, opts={}, &block)
|
142
|
+
first_route, *other_routes = capture_routes { super }
|
143
|
+
first_route.also_change(*other_routes)
|
144
|
+
first_route
|
145
|
+
end
|
146
|
+
|
147
|
+
def route(verb, path, options={}, &block)
|
148
|
+
file, line = block.source_location if block.respond_to? :source_location
|
149
|
+
file ||= caller_files.first
|
150
|
+
route = super(verb, path, options, &block)
|
151
|
+
route.to_route! verb, :app => self, :file => file.expand_path, :line => line, :path => path
|
152
|
+
invoke_hook :advanced_root_added, route
|
153
|
+
@capture_routes << route if @capture_routes
|
154
|
+
route
|
155
|
+
end
|
156
|
+
|
157
|
+
def each_route(&block)
|
158
|
+
return enum_for(:each_route) if respond_to? :enum_for and not block
|
159
|
+
routes.inject([]) { |result, (verb, list)| result.push *list.each(&block) }
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def capture_routes
|
165
|
+
capture_routes_was, @capture_routes = @capture_routes, []
|
166
|
+
yield
|
167
|
+
captured, @capture_routes = @capture_routes, capture_routes_was
|
168
|
+
captured
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.registered(klass)
|
174
|
+
klass.extend ClassMethods
|
175
|
+
klass.routes.each do |verb, routes|
|
176
|
+
routes.each do |route|
|
177
|
+
route.to_route! verb, :app => klass
|
178
|
+
klass.send :invoke_hook, :advanced_root_added, route
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require "sinatra/base"
|
2
|
+
require "monkey-lib"
|
3
|
+
|
4
|
+
class BigBand < Sinatra::Base
|
5
|
+
|
6
|
+
CALLERS_TO_IGNORE = (class << Sinatra::Base; CALLERS_TO_IGNORE; end) unless defined? CALLERS_TO_IGNORE
|
7
|
+
Dir.chdir __FILE__.dirname.dirname do
|
8
|
+
Dir.glob("**/*.rb") { |file| CALLERS_TO_IGNORE << Regexp.new(Regexp.escape(file)) }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Basic Sinatra extension (mainly extending Sinatra's standard methods, like set or register).
|
12
|
+
# Also it features a more advanced path guessing than Sinatra::Base.
|
13
|
+
# Normally you do not have to register this module manually, as the other extensions will do so
|
14
|
+
# if necessary.
|
15
|
+
module BasicExtensions
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
attr_writer :root, :guessed_root
|
19
|
+
|
20
|
+
# More advanced set:
|
21
|
+
# - Adds set_#{key} and set_value hooks to set.
|
22
|
+
# - Merges the old value with the new one, if both are hashes:
|
23
|
+
# set :haml, :format => :html5, :escape_html => true
|
24
|
+
# set :haml, :excape_html => false
|
25
|
+
# haml # => { :format => :html5, :escape_html => false }
|
26
|
+
# - Allowes passing a block:
|
27
|
+
# set(:foo) { Time.now }
|
28
|
+
# - Defines a helper to access #{key} and #{key}? unless a helper/method with that name already exists.
|
29
|
+
def set(key, value = self, &block)
|
30
|
+
# FIXME: refactor, refactor, refactor
|
31
|
+
if block_given?
|
32
|
+
raise ArgumentError, "both a value and a block given" if value != self
|
33
|
+
value = block
|
34
|
+
end
|
35
|
+
symbolized = (key.to_sym if key.respond_to? :to_sym)
|
36
|
+
old_value = (send(symbolized) if symbolized and respond_to? symbolized)
|
37
|
+
value = old_value.merge value if value.is_a? Hash and old_value.is_a? Hash
|
38
|
+
super(key, value)
|
39
|
+
if symbolized
|
40
|
+
method_names = instance_methods.map { |m| m.to_s }
|
41
|
+
define_method(key) { self.class.send(key) } unless method_names.include? key.to_s
|
42
|
+
define_method("#{key}?") { self.class.send("#{key}?") } unless method_names.include? "#{key}?"
|
43
|
+
end
|
44
|
+
# HACK: Sinatra::Base.set uses recursion and in the final step value always
|
45
|
+
# is a Proc. Also, if value is a Proc no step ever follows. I abuse this to
|
46
|
+
# invoke the hooks only once per set.
|
47
|
+
if value.is_a? Proc
|
48
|
+
invoke_hook "set_#{key}", self
|
49
|
+
invoke_hook :set_value, self, key
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
# More advacend register:
|
55
|
+
# - If an exntesion is registered twice, the registered hook will only be called once.
|
56
|
+
def register(*extensions, &block)
|
57
|
+
extensions.reject! { |e| self.extensions.include? e }
|
58
|
+
super(*extensions, &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Short hand so you can skip those ugly File.expand_path(File.join(File.dirname(__FILE__), ...))
|
62
|
+
# lines.
|
63
|
+
def root_path(*args)
|
64
|
+
relative = File.join(*args)
|
65
|
+
return relative if relative.expand_path == relative
|
66
|
+
root.expand_path / relative
|
67
|
+
end
|
68
|
+
|
69
|
+
# Like root_path, but does return an array instead of a string. Optionally takes a block that will
|
70
|
+
# be called for each entry once.
|
71
|
+
#
|
72
|
+
# Example:
|
73
|
+
# class Foo < BigBand
|
74
|
+
# root_glob("app", "{models,views,controllers}", "*.rb") { |file| load file }
|
75
|
+
# end
|
76
|
+
def root_glob(*args, &block)
|
77
|
+
Dir.glob(root_path(*args), &block)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Whether or not to start a webserver.
|
81
|
+
def run?
|
82
|
+
@run ||= true
|
83
|
+
@run and !@running and app_file? and $0.expand_path == app_file.expand_path
|
84
|
+
end
|
85
|
+
|
86
|
+
# Disable automatically running this class as soon it is subclassed.
|
87
|
+
def inherited
|
88
|
+
super
|
89
|
+
@run = false
|
90
|
+
end
|
91
|
+
|
92
|
+
# The application's root directory. BigBand will guess if missing.
|
93
|
+
def root
|
94
|
+
return ".".expand_path unless app_file?
|
95
|
+
return @root if @root
|
96
|
+
@guessed_root ||= begin
|
97
|
+
dir = app_file.expand_path.dirname
|
98
|
+
if dir.basename == "lib" and not (dir / "lib").directory?
|
99
|
+
dir.dirname
|
100
|
+
else
|
101
|
+
dir
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns true if the #root is known.
|
107
|
+
def root?
|
108
|
+
!!@root || app_file?
|
109
|
+
end
|
110
|
+
|
111
|
+
# Option parser for #run!
|
112
|
+
def run_option_parser
|
113
|
+
@run_option_parser ||= begin
|
114
|
+
require 'optparse'
|
115
|
+
OptionParser.new do |op|
|
116
|
+
op.on('-x') { set :lock, true }
|
117
|
+
op.on('-e env') { |val| set :environment, val.to_sym }
|
118
|
+
op.on('-s server') { |val| set :server, val }
|
119
|
+
op.on('-p port') { |val| set :port, val.to_i }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Extended #run!, offers an extandable option parser for
|
125
|
+
# BigBand with the same standard options as the one of
|
126
|
+
# Sinatra#Default (see #run_option_parser).
|
127
|
+
def run!(options = {})
|
128
|
+
run_option_parser.parse!(ARGV.dup) unless ARGV.empty?
|
129
|
+
@running = true
|
130
|
+
super(options)
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
module InstanceMethods
|
136
|
+
|
137
|
+
# See BigBand::BasicExtentions::ClassMethods#root_path
|
138
|
+
def root_path(*args)
|
139
|
+
self.class.root_path(*args)
|
140
|
+
end
|
141
|
+
|
142
|
+
# See BigBand::BasicExtentions::ClassMethods#root_path
|
143
|
+
def root_glob(*args, &block)
|
144
|
+
self.class.root_glob(*args, &block)
|
145
|
+
end
|
146
|
+
|
147
|
+
# See BigBand::BasicExtentions::ClassMethods#root
|
148
|
+
def root
|
149
|
+
self.class.root
|
150
|
+
end
|
151
|
+
|
152
|
+
# See BigBand::BasicExtentions::ClassMethods#root?
|
153
|
+
def root?
|
154
|
+
self.class.root
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.registered(klass)
|
160
|
+
klass.set :app_file, klass.caller_files.first.expand_path unless klass.app_file?
|
161
|
+
klass.extend ClassMethods
|
162
|
+
klass.send :include, InstanceMethods
|
163
|
+
klass.set :haml, :format => :html5, :escape_html => true
|
164
|
+
klass.use Rack::Session::Cookie
|
165
|
+
klass.enable :sessions
|
166
|
+
klass.get %r{/__big_band__/([^\.]+(\.[^\.]+)?)} do
|
167
|
+
send_file(__FILE__.expand_path.dirname / :files / params[:captures].first)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.set_app_file(klass)
|
172
|
+
klass.guessed_root = nil
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
@import big_band/utilities.sass
|
@@ -0,0 +1 @@
|
|
1
|
+
@import blueprint/html5.sass
|
@@ -0,0 +1,103 @@
|
|
1
|
+
@import ../utilities.sass
|
2
|
+
@import blueprint.sass
|
3
|
+
@import blueprint/screen.sass
|
4
|
+
@import blueprint/modules/fancy_type.sass
|
5
|
+
@import blueprint/modules/scaffolding.sass
|
6
|
+
@import blueprint/modules/typography.sass
|
7
|
+
|
8
|
+
=layout_inspector
|
9
|
+
+html5
|
10
|
+
+blueprint-typography
|
11
|
+
+fancy-paragraphs
|
12
|
+
body
|
13
|
+
padding: 5em 1em
|
14
|
+
background-color: #ddd
|
15
|
+
color
|
16
|
+
header
|
17
|
+
+box-shadow(0 2px 15px rgba(0, 0, 0, 0.8))
|
18
|
+
padding: 0px 10px
|
19
|
+
text-align: right
|
20
|
+
font-size: 80%
|
21
|
+
background:
|
22
|
+
color: rgba(0, 0, 0, 0.5)
|
23
|
+
image: url(/__big_band__/overlay-button.png)
|
24
|
+
repeat: repeat-x
|
25
|
+
border-bottom: solid 2px #333
|
26
|
+
color: #333
|
27
|
+
position: fixed
|
28
|
+
top: 0
|
29
|
+
right: 0
|
30
|
+
width: 100%
|
31
|
+
nav
|
32
|
+
a
|
33
|
+
+fancy-button-link(#040, 20px, 100px)
|
34
|
+
margin: 5px
|
35
|
+
h1
|
36
|
+
font:
|
37
|
+
weight: 500
|
38
|
+
size: 40px
|
39
|
+
margin: 0px
|
40
|
+
float: left
|
41
|
+
padding-left: 20px
|
42
|
+
color: #333
|
43
|
+
text-shadow: 0px 1px 2px rgba(0,0,0,0.8), -1px -1px 3px #eee, 0px 0px 8px rgba(0,0,0,0.7)
|
44
|
+
h2
|
45
|
+
font:
|
46
|
+
weight: bold
|
47
|
+
size: 130%
|
48
|
+
border-bottom: dotted 1px #bbb
|
49
|
+
width: 500px
|
50
|
+
table
|
51
|
+
+box-shadow(0px 3px 10px rgba(0,0,0,0.7))
|
52
|
+
border: solid 1px #555
|
53
|
+
background:
|
54
|
+
color: #fff
|
55
|
+
image: url(/__big_band__/overlay-button.png)
|
56
|
+
padding: 0px
|
57
|
+
width: 80%
|
58
|
+
margin: 0px 10%
|
59
|
+
tr
|
60
|
+
th, td
|
61
|
+
padding:
|
62
|
+
bottom: 0
|
63
|
+
top: 0
|
64
|
+
left: 5px
|
65
|
+
right: 20px
|
66
|
+
th
|
67
|
+
background-color: #555
|
68
|
+
color: #fff
|
69
|
+
font:
|
70
|
+
weight: bold
|
71
|
+
size: 90%
|
72
|
+
td
|
73
|
+
border:
|
74
|
+
color: #ddd
|
75
|
+
style: solid
|
76
|
+
width: 0px
|
77
|
+
left-width: 1px
|
78
|
+
min-width: 80px
|
79
|
+
footer
|
80
|
+
margin-top: 20px
|
81
|
+
+alt
|
82
|
+
a
|
83
|
+
color: #040
|
84
|
+
text-decoration: none
|
85
|
+
&:hover, &:visited
|
86
|
+
color: #040
|
87
|
+
&:hover
|
88
|
+
text-decoration: underline
|
89
|
+
.note
|
90
|
+
+box-shadow(0px 3px 10px rgba(0,0,0,0.7))
|
91
|
+
+border-radius
|
92
|
+
margin:
|
93
|
+
top: 5px
|
94
|
+
left: 10%
|
95
|
+
right: 10%
|
96
|
+
bottom: 20px
|
97
|
+
padding: 2px
|
98
|
+
background-color: #eee
|
99
|
+
text-align: center
|
100
|
+
font-size: 110%
|
101
|
+
a
|
102
|
+
font-weight: bold
|
103
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
@import "css3_prefix.sass"
|
2
|
+
|
3
|
+
!default_border_radius = 10px
|
4
|
+
|
5
|
+
=border-radius(!lt = "auto", !rt = "auto", !rb = "auto", !lb = "auto")
|
6
|
+
@if !lt == "auto"
|
7
|
+
!lt = !default_border_radius
|
8
|
+
@if !rt == "auto"
|
9
|
+
!rt = !lt
|
10
|
+
@if !rb == "auto"
|
11
|
+
!rb = !lt
|
12
|
+
@if !lb == "auto"
|
13
|
+
!lb = !rt
|
14
|
+
min-width = max(!lt + !rt, !lb + !rb)
|
15
|
+
min-height = max(!lt + !lb, !rt + !rb)
|
16
|
+
+border-radius-no-min-size(!lt, !rt, !rb, !lb)
|
17
|
+
|
18
|
+
=border-radius-no-min-size(!lt, !rt, !rb, !lb)
|
19
|
+
+prefixed("border-top-left-radius", !lt)
|
20
|
+
+prefixed("border-top-right-radius", !rt)
|
21
|
+
+prefixed("border-bottom-left-radius", !lb)
|
22
|
+
+prefixed("border-bottom-right-radius", !rb)
|
23
|
+
-moz-border-radius:
|
24
|
+
topleft = !lt
|
25
|
+
topright = !rt
|
26
|
+
bottomright = !rb
|
27
|
+
bottomleft = !lb
|
@@ -0,0 +1,14 @@
|
|
1
|
+
=prefixed(!attribute, !value)
|
2
|
+
-moz-#{!attribute} = !value
|
3
|
+
-webkit-#{!attribute} = !value
|
4
|
+
-khtml-#{!attribute} = !value
|
5
|
+
-ms-#{!attribute} = !value
|
6
|
+
-o-#{!attribute} = !value
|
7
|
+
#{!attribute} = !value
|
8
|
+
|
9
|
+
=box-shadow(!parameters)
|
10
|
+
+prefixed(box-shadow, !parameters)
|
11
|
+
|
12
|
+
=transition(!property, !duration)
|
13
|
+
+prefixed("transition-property", !property)
|
14
|
+
+prefixed("transition-duration", !duration)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
@import border_radius.sass
|
2
|
+
@import css3_prefix.sass
|
3
|
+
|
4
|
+
!fancy_button_color = #222
|
5
|
+
!fancy_button_height = 30px
|
6
|
+
!fancy_button_width = "auto"
|
7
|
+
!fancy_button_radius = "auto"
|
8
|
+
!fancy_button_darkening = 0.3
|
9
|
+
|
10
|
+
=fancy-button(!color = !fancy_button_color, !height = !fancy_button_height, !width = !fancy_button_width, !radius = !fancy_button_radius)
|
11
|
+
@if !radius == "auto"
|
12
|
+
!radius = !height
|
13
|
+
@if !height < !radius * 2
|
14
|
+
!radius = !height / 2
|
15
|
+
+border-radius(!radius)
|
16
|
+
+box-shadow(0 1px 10px rgba(0, 0, 0, 0.6))
|
17
|
+
text-shadow = 0 -1px (!height * 0.1) rgba(0,0,0,0.7)
|
18
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.25)
|
19
|
+
background:
|
20
|
+
color = !color
|
21
|
+
image: url(/__big_band__/overlay-button.png)
|
22
|
+
repeat: repeat-x
|
23
|
+
attachment: scroll
|
24
|
+
position:
|
25
|
+
top: 0
|
26
|
+
left: 0
|
27
|
+
display: inline-block
|
28
|
+
padding = (!height * 0.1 - 1px) (!height * 0.5)
|
29
|
+
color: #fff !important
|
30
|
+
text:
|
31
|
+
decoration: none
|
32
|
+
align: center
|
33
|
+
-moz-background:
|
34
|
+
clip: border
|
35
|
+
inline-policy: continuous
|
36
|
+
font:
|
37
|
+
family: Arial,Helvetica,Helvetica Neue,Verdana,sans-serif
|
38
|
+
weight: bold
|
39
|
+
size = !height * 0.8
|
40
|
+
height = !height !important
|
41
|
+
width = !width
|
42
|
+
line-height: 1.2
|
43
|
+
|
44
|
+
=fancy-button-link(!color = !fancy_button_color, !height = !fancy_button_height, !width = !fancy_button_width, !radius = !fancy_button_radius, !darkening = !fancy_button_darkening)
|
45
|
+
!offset = !height * 0.1 + 3px
|
46
|
+
+fancy-button(!color, !height, !width, !radius)
|
47
|
+
+prefixed("transition-property", "background, left, top, box-shadow, -moz-box-shadow, -webkit-box-shadow")
|
48
|
+
+prefixed("transition-duration", "0.5s")
|
49
|
+
position: relative
|
50
|
+
top: 0
|
51
|
+
left: 0
|
52
|
+
cursor: pointer
|
53
|
+
margin = !offset
|
54
|
+
&:hover
|
55
|
+
+fancy-button(!color * !darkening, !height, !width, !radius)
|
56
|
+
+box-shadow(!offset !offset + 1px !offset + 10px rgba(0, 0, 0, 0.5))
|
57
|
+
left = -!offset
|
58
|
+
top = -!offset
|
59
|
+
&:visited, &:hover
|
60
|
+
color = !color
|
61
|
+
text-decoration: none
|
62
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "sinatra/base"
|
2
|
+
require "big_band/basic_extensions"
|
3
|
+
require "big_band/advanced_routes"
|
4
|
+
require "big_band/compass/big_band"
|
5
|
+
require "big_band/sass"
|
6
|
+
|
7
|
+
class BigBand < Sinatra::Base
|
8
|
+
|
9
|
+
# Integrates the Compass stylesheet framework with Sinatra.
|
10
|
+
#
|
11
|
+
# Usage without doing something:
|
12
|
+
#
|
13
|
+
# require "big_band"
|
14
|
+
# class Foo < BigBand; end
|
15
|
+
#
|
16
|
+
# If you create a directory called views/stylesheets and place your
|
17
|
+
# sass files in there, there you go. Just call stylesheet(name) form
|
18
|
+
# your view to get the correct stylesheet tag. The URL for your
|
19
|
+
# stylesheets will be /stylesheets/:name.css.
|
20
|
+
#
|
21
|
+
# Of course you can use any other setup. Say, you want to store your
|
22
|
+
# stylesheets in views/css and want the URL to be /css/:name.css:
|
23
|
+
#
|
24
|
+
# class Foo < BigBand
|
25
|
+
# get_compass("css")
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# But what about more complex setups?
|
29
|
+
#
|
30
|
+
# class Foo < BigBand
|
31
|
+
# set :compass, :sass_dir => "/foo/bar/blah"
|
32
|
+
# get_compass("/foo/:name.css") do
|
33
|
+
# compass :one_stylesheet
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# Note that already generated routes will be deactivated by calling
|
38
|
+
# get_compass again.
|
39
|
+
module Compass
|
40
|
+
|
41
|
+
module ClassMethods
|
42
|
+
attr_reader :compass_route
|
43
|
+
def get_compass(path, &block)
|
44
|
+
block ||= Proc.new do |file|
|
45
|
+
content_type 'text/css', :charset => 'utf-8'
|
46
|
+
compass :"#{path}/#{params[:name]}"
|
47
|
+
end
|
48
|
+
set :compass, :sass_dir => klass.views / path unless compass[:sass_dir] && compass[:sass_dir].directory?
|
49
|
+
@compass_route.deactivate if @compass_route
|
50
|
+
@compass_route = get("/#{path}" / ":name.css", &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module InstanceMethods
|
55
|
+
def compass(file, options = {})
|
56
|
+
options.merge! ::Compass.sass_engine_options
|
57
|
+
sass file, options
|
58
|
+
end
|
59
|
+
def stylesheet(*args)
|
60
|
+
raise NotImplementedError, "yet to be implemented"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.registered(klass)
|
65
|
+
klass.register BasicExtensions
|
66
|
+
klass.register AdvancedRoutes
|
67
|
+
klass.extend ClassMethods
|
68
|
+
klass.send :include, InstanceMethods
|
69
|
+
klass.set :compass,
|
70
|
+
:project_path => klass.root_path, :output_style => (klass.development? ? :expanded : :compressed),
|
71
|
+
:sass_dir => klass.views / "stylesheets", :line_comments => klass.development?
|
72
|
+
set_app_file(klass) if klass.app_file?
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.set_app_file(klass)
|
76
|
+
klass.set :compass, :root_path => klass.root_path
|
77
|
+
klass.get_compass("stylesheets") if (klass.views / "stylesheets").directory?
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.set_compass(klass)
|
81
|
+
::Compass.configuration do |config|
|
82
|
+
config.sass_options ||= {}
|
83
|
+
klass.compass.each do |option, value|
|
84
|
+
if config.respond_to? option
|
85
|
+
config.send "#{option}=", value
|
86
|
+
else
|
87
|
+
config.sass_options.merge! option.to_sym => value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
Binary file
|