restapi_doc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'activesupport', '>= 2.1'
4
+ gem 'haml', '3.1.4'
5
+
6
+ group :development do
7
+ gem 'rake'
8
+ gem 'jeweler'
9
+ gem 'rspec', '>= 2.2.0'
10
+ gem 'mocha'
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ git (1.2.5)
6
+ haml (3.1.4)
7
+ jeweler (1.8.3)
8
+ bundler (~> 1.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ rdoc
12
+ json (1.6.6)
13
+ metaclass (0.0.1)
14
+ mocha (0.11.3)
15
+ metaclass (~> 0.0.1)
16
+ rake (0.9.2.2)
17
+ rdoc (3.12)
18
+ json (~> 1.4)
19
+ rspec (2.9.0)
20
+ rspec-core (~> 2.9.0)
21
+ rspec-expectations (~> 2.9.0)
22
+ rspec-mocks (~> 2.9.0)
23
+ rspec-core (2.9.0)
24
+ rspec-expectations (2.9.1)
25
+ diff-lcs (~> 1.1.3)
26
+ rspec-mocks (2.9.0)
27
+
28
+ PLATFORMS
29
+ ruby
30
+
31
+ DEPENDENCIES
32
+ haml (= 3.1.4)
33
+ jeweler
34
+ mocha
35
+ rake
36
+ rspec (>= 2.2.0)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Kevin Haight (kevinjhaight@gmail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,28 @@
1
+ = Rest Api Doc
2
+
3
+ Rest API doc generates an easy way to create a Twitter style document for your RESTful interface
4
+
5
+ Leveraging Twitter Bootstrap to create an easy to read document for your RESTful api.
6
+
7
+ == Installing the gem
8
+
9
+ gem install restapi_doc
10
+
11
+ == Set Up
12
+ Run the following rake command to setup your environment.
13
+
14
+ rake restapi_doc:generate
15
+
16
+ This will create a 'restapi_doc' directory in your Rails config directory.
17
+ In this directory you will now have a "restapi_doc.yml' file with some simple configuration options for your API document.
18
+
19
+
20
+ == Documenting controllers
21
+ Below is a sample of how to document the controller to generate a document
22
+
23
+
24
+ == Creating Api Document
25
+
26
+ rake restapi_doc:generate
27
+
28
+ You will now have a 'apidoc' directory located in your Rails 'public' directory
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "restapi_doc"
8
+ gem.summary = %Q{REST API doc generates an easy way to create a twitter style document for your RESTful interface}
9
+ gem.description = %Q{REST API doc generates an easy way to create a twitter style document for your RESTful interface.
10
+ Leveraging Twitter Bootstrap to create an easy to read document for your RESTful api. }
11
+ gem.email = "kevinjhaight@gmail.com"
12
+ gem.homepage = "http://github.com/alayho/restapi_doc"
13
+ gem.authors = ["Kevin Haight"]
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rspec/core/rake_task'
21
+ RSpec::Core::RakeTask.new(:spec) do |spec|
22
+ spec.pattern = 'spec/**/*_spec.rb'
23
+ end
24
+
25
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
26
+ spec.pattern = 'spec/**/*_spec.rb'
27
+ spec.rcov = true
28
+ end
29
+
30
+ task :default => :spec
31
+
32
+ require 'rdoc/task'
33
+ Rake::RDocTask.new do |rdoc|
34
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
35
+ rdoc.rdoc_dir = 'rdoc'
36
+ rdoc.title = "restapi_doc #{version}"
37
+ rdoc.rdoc_files.include('README*')
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,2 @@
1
+ project_name: "RESTful API"
2
+ base_url: "http://api.mydomain.com"
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+ module RestApiDoc
3
+ module Config
4
+ def template_dir(f = nil)
5
+ @template_dir ||= File.join(File.dirname(__FILE__), 'template')
6
+ form_file_name @template_dir, f
7
+ end
8
+
9
+ def config_template_dir(f = nil)
10
+ @template_dir ||= File.join(File.dirname(__FILE__), 'config')
11
+ form_file_name @template_dir, f
12
+ end
13
+
14
+ def asset_dir
15
+ @asset_dir ||= File.join(File.dirname(__FILE__), 'template/assets')
16
+ end
17
+
18
+ def config_dir(f = nil)
19
+ @config_dir ||= File.join(::Rails.root.to_s, 'config/restapi_doc')
20
+ form_file_name @config_dir, f
21
+ end
22
+
23
+ def target_dir(f = nil)
24
+ @target_dir ||= File.join(::Rails.root.to_s, 'public/apidoc/')
25
+ form_file_name @target_dir, f
26
+ end
27
+
28
+ def controller_dir(f = nil)
29
+ @controller_dir ||= File.join(::Rails.root.to_s, 'app/controllers/')
30
+ form_file_name @controller_dir, f
31
+ end
32
+
33
+ def temp_dir(f = nil)
34
+ @temp_dir ||= "#{Dir.mktmpdir("apidoc")}/"
35
+ form_file_name @temp_dir, f
36
+ end
37
+
38
+ def form_file_name(dir, file)
39
+ case file
40
+ when NilClass then dir
41
+ when String then File.join(dir, file)
42
+ else raise ArgumentError, "Invalid argument #{file}"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+ module RestApiDoc
3
+ class MethodDoc
4
+ attr_accessor :scope, :method_order, :content, :request, :response, :output, :params, :defname, :response_formats, :requires_authentication, :request_url, :account_password_required, :http_responses
5
+
6
+ def initialize(resource_name, type, order)
7
+ @resource_name = resource_name
8
+ @scope = type
9
+ @method_order = order
10
+ @content = ""
11
+ @request = ""
12
+ @response = ""
13
+ @output = ""
14
+ @params = []
15
+ @response_formats = []
16
+ @http_responses= []
17
+ @requires_authentication = "No"
18
+ @account_password_required = "No"
19
+ @defname = nil
20
+ @request_url = nil
21
+ end
22
+
23
+ def process_line(line, current_scope)
24
+ new_scope = current_scope
25
+ case current_scope
26
+ when :response
27
+ if line =~ /::response-end::/
28
+ new_scope = :function
29
+ else
30
+ @response << line
31
+ end
32
+ when :request
33
+ if line =~ /::request-end::/
34
+ new_scope = :function
35
+ else
36
+ @request << line
37
+ end
38
+ when :output # append output
39
+ if line =~ /::output-end::/
40
+ new_scope = :function
41
+ else
42
+ @output << line
43
+ end
44
+ when :class, :function
45
+ result = line.scan(/(\w+)\:\:\s*(.+)/)
46
+ if not result.empty?
47
+ key, value = result[0]
48
+ case key
49
+ when "response", "request"
50
+ new_scope = key.to_sym
51
+ when "output"
52
+ new_scope = key.to_sym
53
+ when "param"
54
+ @params << value
55
+ when "http_response"
56
+ @http_responses << value
57
+ when "response_format"
58
+ @response_formats << value
59
+ when "requires_authentication"
60
+ @requires_authentication = value
61
+ when "request_url"
62
+ @request_url = value
63
+ when "account_password_required"
64
+ @account_password_required = value
65
+ else # user wants this new shiny variable whose name is the key with value = value
66
+ instance_variable_set("@#{key}".to_sym, value)
67
+ define_singleton_method(key.to_sym) { value } # define accessor for the templates to read it
68
+ end
69
+ else
70
+ # add line to block
71
+ @content << line
72
+ end
73
+ else
74
+ raise ParsingException, "logic error: unknown current scope #{current_scope}"
75
+ end
76
+ new_scope
77
+ end
78
+
79
+ def get_binding
80
+ binding
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+ require 'rails'
3
+ module RestApiDoc
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ load 'restapi_doc/tasks/restapi_doc_tasks.rake'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+ require_relative 'method_doc'
3
+
4
+ module RestApiDoc
5
+ class ParsingException < Exception;
6
+ end
7
+ class ResourceDoc
8
+
9
+ attr_reader :name, :resource_location, :controller_name, :class_block, :function_blocks, :resource_header, :resource_methods, :description
10
+
11
+ # Initializes ResourceDoc.
12
+ def initialize(name, action_methods, controller_location, options = {})
13
+ @name = name
14
+ @class_block = nil
15
+ @function_blocks = []
16
+ @resource_methods = action_methods
17
+ @resource_header = ""
18
+ @standard_methods = options[:standard_methods] || [:put, :post, :get, :delete]
19
+ @resource_location = resource_location
20
+ @controller_location = controller_location
21
+ @description = nil
22
+ @controller_name = File.basename(controller_location)
23
+ end
24
+
25
+ # parse the controller
26
+ def parse_apidoc
27
+ lines = IO.readlines(@controller_location)
28
+ begin
29
+ @class_block, @function_blocks = ResourceDoc.parse_controller_doc(@name, lines)
30
+ rescue ParsingException => ex
31
+ puts "error #{ex} while parsing #{@controller_location}"
32
+ exit
33
+ end
34
+ if !@class_block.nil?
35
+ @description = @class_block.content
36
+ end
37
+
38
+ @resource_methods.each do | req_m |
39
+ req_m << @function_blocks.select{|f| f.defname == req_m[0]}.first
40
+ end
41
+ end
42
+
43
+ # This method parses the doc
44
+ def self.parse_controller_doc(name, lines)
45
+ current_api_block = nil
46
+ current_scope = :none
47
+ in_class = false
48
+ class_block = nil
49
+ function_blocks = []
50
+ order = 1
51
+ lines.each_with_index do |line, line_no|
52
+ line.gsub!(/^ *#/, '') # strip the starting '#' on the line
53
+ case line
54
+ when /=begin apidoc/
55
+ # if we get apidoc tag inside class definition, then they are for a method
56
+ current_scope = !in_class ? :class : :function
57
+ current_api_block = MethodDoc.new(name, current_scope, order)
58
+ when /=end/
59
+ if current_api_block.nil?
60
+ raise ParsingException, "#{line_no} - No starttag for '=end' found"
61
+ end
62
+ when /class/ # keep track of whether a resource or an api is being annotated
63
+ in_class = true
64
+ if !current_api_block.nil?
65
+ case current_scope
66
+ when :class
67
+ class_block = current_api_block
68
+ when :function
69
+ function_blocks << current_api_block
70
+ else
71
+ raise ParsingException, "logic error: unknown current scope #{current_scope}"
72
+ end
73
+
74
+ current_api_block = nil
75
+ current_scope = :none
76
+ order += 1
77
+ end
78
+ when /def/
79
+ if !current_api_block.nil?
80
+ current_api_block.defname = line.gsub('def ', '').strip
81
+
82
+ case current_scope
83
+ when :class
84
+ class_block = current_api_block
85
+ when :function
86
+ function_blocks << current_api_block
87
+ else
88
+ raise ParsingException, "logic error: unknown current scope #{current_scope}"
89
+ end
90
+
91
+ current_api_block = nil
92
+ current_scope = :none
93
+ order += 1
94
+ end
95
+ else
96
+ if current_api_block # process lines only if they are apidoc comments
97
+ current_scope = current_api_block.process_line(line, current_scope)
98
+ end
99
+ end
100
+ end
101
+ [class_block, function_blocks]
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ include RestApiDoc
3
+
4
+ namespace :restapi_doc do
5
+
6
+ desc "Generate the config files"
7
+ task :setup do
8
+ create_structure
9
+ end
10
+
11
+ desc "Generate the api documentation"
12
+ task :generate do
13
+ remove_structure
14
+ resources = get_resources do |controller, controller_url, controller_location|
15
+ end
16
+ if !resources.empty?
17
+ puts "Generating API documentation..."
18
+ generate_doc(resources)
19
+ move_document
20
+ puts "Completed API documentation generation"
21
+ end
22
+ end
23
+
24
+ desc "Generate the config files"
25
+ task :clean do
26
+ remove_structure
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ .clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
2
+ .clearfix:after{clear:both;}
3
+ .hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;}
4
+ .input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
5
+ .hidden{display:none;visibility:hidden;}
6
+ .visible-phone{display:none;}
7
+ .visible-tablet{display:none;}
8
+ .visible-desktop{display:block;}
9
+ .hidden-phone{display:block;}
10
+ .hidden-tablet{display:block;}
11
+ .hidden-desktop{display:none;}
12
+ @media (max-width:767px){.visible-phone{display:block;} .hidden-phone{display:none;} .hidden-desktop{display:block;} .visible-desktop{display:none;}}@media (min-width:768px) and (max-width:979px){.visible-tablet{display:block;} .hidden-tablet{display:none;} .hidden-desktop{display:block;} .visible-desktop{display:none;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:18px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{position:absolute;top:10px;left:10px;right:10px;width:auto;margin:0;}.modal.fade.in{top:auto;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top{margin-left:-20px;margin-right:-20px;} .container{width:auto;} .row-fluid{width:100%;} .row{margin-left:0;} .row>[class*="span"],.row-fluid>[class*="span"]{float:none;display:block;width:auto;margin:0;} .thumbnails [class*="span"]{width:auto;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} .input-prepend input[class*="span"],.input-append input[class*="span"]{width:auto;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.762430939%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid > .span12{width:99.999999993%;} .row-fluid > .span11{width:91.436464082%;} .row-fluid > .span10{width:82.87292817100001%;} .row-fluid > .span9{width:74.30939226%;} .row-fluid > .span8{width:65.74585634900001%;} .row-fluid > .span7{width:57.182320438000005%;} .row-fluid > .span6{width:48.618784527%;} .row-fluid > .span5{width:40.055248616%;} .row-fluid > .span4{width:31.491712705%;} .row-fluid > .span3{width:22.928176794%;} .row-fluid > .span2{width:14.364640883%;} .row-fluid > .span1{width:5.801104972%;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:714px;} input.span11, textarea.span11, .uneditable-input.span11{width:652px;} input.span10, textarea.span10, .uneditable-input.span10{width:590px;} input.span9, textarea.span9, .uneditable-input.span9{width:528px;} input.span8, textarea.span8, .uneditable-input.span8{width:466px;} input.span7, textarea.span7, .uneditable-input.span7{width:404px;} input.span6, textarea.span6, .uneditable-input.span6{width:342px;} input.span5, textarea.span5, .uneditable-input.span5{width:280px;} input.span4, textarea.span4, .uneditable-input.span4{width:218px;} input.span3, textarea.span3, .uneditable-input.span3{width:156px;} input.span2, textarea.span2, .uneditable-input.span2{width:94px;} input.span1, textarea.span1, .uneditable-input.span1{width:32px;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top{position:static;margin-bottom:18px;} .navbar-fixed-top .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .navbar .nav-collapse{clear:left;} .navbar .nav{float:none;margin:0 0 9px;} .navbar .nav>li{float:none;} .navbar .nav>li>a{margin-bottom:2px;} .navbar .nav>.divider-vertical{display:none;} .navbar .nav .nav-header{color:#999999;text-shadow:none;} .navbar .nav>li>a,.navbar .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .navbar .dropdown-menu li+li a{margin-bottom:2px;} .navbar .nav>li>a:hover,.navbar .dropdown-menu a:hover{background-color:#222222;} .navbar .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .navbar .dropdown-menu:before,.navbar .dropdown-menu:after{display:none;} .navbar .dropdown-menu .divider{display:none;} .navbar-form,.navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222222;border-bottom:1px solid #222222;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);} .navbar .nav.pull-right{float:none;margin-left:0;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;} .btn-navbar{display:block;} .nav-collapse{overflow:hidden;height:0;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:30px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.564102564%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid > .span12{width:100%;} .row-fluid > .span11{width:91.45299145300001%;} .row-fluid > .span10{width:82.905982906%;} .row-fluid > .span9{width:74.358974359%;} .row-fluid > .span8{width:65.81196581200001%;} .row-fluid > .span7{width:57.264957265%;} .row-fluid > .span6{width:48.717948718%;} .row-fluid > .span5{width:40.170940171000005%;} .row-fluid > .span4{width:31.623931624%;} .row-fluid > .span3{width:23.076923077%;} .row-fluid > .span2{width:14.529914530000001%;} .row-fluid > .span1{width:5.982905983%;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:1160px;} input.span11, textarea.span11, .uneditable-input.span11{width:1060px;} input.span10, textarea.span10, .uneditable-input.span10{width:960px;} input.span9, textarea.span9, .uneditable-input.span9{width:860px;} input.span8, textarea.span8, .uneditable-input.span8{width:760px;} input.span7, textarea.span7, .uneditable-input.span7{width:660px;} input.span6, textarea.span6, .uneditable-input.span6{width:560px;} input.span5, textarea.span5, .uneditable-input.span5{width:460px;} input.span4, textarea.span4, .uneditable-input.span4{width:360px;} input.span3, textarea.span3, .uneditable-input.span3{width:260px;} input.span2, textarea.span2, .uneditable-input.span2{width:160px;} input.span1, textarea.span1, .uneditable-input.span1{width:60px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;}}
@@ -0,0 +1,9 @@
1
+ @bodyBackground: #FFFFFF;
2
+ @navBar: #ccccc;
3
+ body {
4
+ background: @bodyBackground !important;
5
+ }
6
+
7
+ .navbar-inner{
8
+ background: @navBar !important;
9
+ }