├── .ruby-version ├── Procfile ├── lib ├── css2sass │ ├── version.rb │ ├── convert.rb │ ├── render.rb │ ├── app.rb │ └── flash.rb └── css2sass.rb ├── public ├── images │ ├── favicon.ico │ ├── conv-arr.svg │ ├── sass-icon.svg │ └── scss-icon.svg └── stylesheets │ ├── text.css │ ├── reset.css │ ├── app.css │ └── 960.css ├── .gitignore ├── Guardfile ├── .autotest ├── config.ru ├── config └── puma.rb ├── Gemfile ├── CHANGELOG.md ├── views ├── index.haml └── layout.haml ├── readme.md ├── Gemfile.lock └── test └── test_css2sass.rb /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.6.4 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec puma -C config/puma.rb 2 | -------------------------------------------------------------------------------- /lib/css2sass/version.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | module Css2sass 3 | VERSION = '0.2.1' 4 | end 5 | -------------------------------------------------------------------------------- /lib/css2sass.rb: -------------------------------------------------------------------------------- 1 | %w(flash convert render app version).each { |l| require_relative 'css2sass/' + l } 2 | -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpablobr/css2sass/HEAD/public/images/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | .DS_Store 3 | */.DS_Store 4 | log/*.log 5 | .lock 6 | tmp/* 7 | TAGS 8 | .env 9 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | guard 'bundler' do 4 | watch('Gemfile') 5 | end -------------------------------------------------------------------------------- /.autotest: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | 3 | require 'autotest/restart' 4 | require 'autotest/timestamp' 5 | 6 | Autotest.add_hook :initialize do |at| 7 | at.testlib = 'minitest/unit' 8 | at.unit_diff 9 | end 10 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path('../', __FILE__) 2 | require 'rubygems' 3 | require 'sinatra' 4 | require './lib/css2sass' 5 | 6 | use Rack::Session::Cookie, :key => 'rack.session', 7 | :expire_after => 2592000, 8 | :secret => ENV['RACK_SESSION_COOKIE'] 9 | 10 | run Css2sass::App 11 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | workers Integer(ENV['WEB_CONCURRENCY'] || 2) 2 | threads_count = Integer(ENV['MAX_THREADS'] || 5) 3 | threads threads_count, threads_count 4 | 5 | preload_app! 6 | 7 | rackup DefaultRackup 8 | port ENV['PORT'] || 3000 9 | environment ENV['RACK_ENV'] || 'development' 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | ruby '2.6.4' 4 | 5 | gem 'sinatra' 6 | gem 'hpricot' 7 | gem 'haml' 8 | gem 'sass' 9 | gem 'json' 10 | gem 'builder' 11 | gem 'erubis' 12 | gem 'ruby_parser' 13 | gem 'sinatra-redirect-with-flash' 14 | gem 'puma' 15 | gem 'foreman' 16 | 17 | group :test do 18 | gem 'rack-test' 19 | end 20 | -------------------------------------------------------------------------------- /public/stylesheets/text.css: -------------------------------------------------------------------------------- 1 | body{font:13px/1.5 'Helvetica Neue',Arial,'Liberation Sans',FreeSans,sans-serif}a:focus{outline:1px dotted}hr{border:0 #ccc solid;border-top-width:1px;clear:both;height:0}h1{font-size:25px}h2{font-size:23px}h3{font-size:21px}h4{font-size:19px}h5{font-size:17px}h6{font-size:15px}ol{list-style:decimal}ul{list-style:disc}li{margin-left:30px}p,dl,hr,h1,h2,h3,h4,h5,h6,ol,ul,pre,table,address,fieldset{margin-bottom:20px} -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.2.0 (21/Sep/11) 2 | 3 | - Refactored app... css2sass has been breaked into several proper objects. 4 | 5 | ## 0.1.2 (21/Sep/11) 6 | 7 | - Migrated tests to minitest. 8 | 9 | ## 0.1.1 (Jun 21, 2011) 10 | 11 | - Added spec dir for setting up a better testing environment. 12 | 13 | ## 0.1.0 (Jun 21, 2011) 14 | 15 | - Updated readme, to many grammar error :/ 16 | - `type.eql?("Convert 2 SCSS")` 17 | Stupid mistake, now it can convert properly to scss 18 | - added VERSION and CHANGELOG 19 | -------------------------------------------------------------------------------- /lib/css2sass/convert.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'sass/css' 3 | module Css2sass 4 | class Convert 5 | 6 | def initialize(css) 7 | @css = css 8 | end 9 | 10 | def to_sass 11 | begin 12 | Sass::CSS.new(@css).render(:sass) 13 | rescue Sass::SyntaxError => e 14 | @error = e 15 | end 16 | end 17 | 18 | def to_scss 19 | begin 20 | Sass::CSS.new(@css).render(:scss) 21 | rescue Sass::SyntaxError => e 22 | @error = e 23 | end 24 | end 25 | 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /public/images/conv-arr.svg: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/stylesheets/reset.css: -------------------------------------------------------------------------------- 1 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0} -------------------------------------------------------------------------------- /lib/css2sass/render.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'json' 3 | module Css2sass 4 | class Render 5 | 6 | def initialize(css=nil, output=nil) 7 | @css, @output = css, output 8 | end 9 | 10 | def xml 11 | xml = Builder::XmlMarkup.new 12 | xml.instruct! 13 | xml.page do 14 | xml.css do 15 | xml.cdata! @css.to_s 16 | end 17 | xml.sass do 18 | xml.cdata! @output.to_s 19 | end 20 | end 21 | end 22 | 23 | def json 24 | {:page => 25 | {:css => @css, 26 | :sass => @output 27 | } 28 | }.to_json 29 | end 30 | 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /views/index.haml: -------------------------------------------------------------------------------- 1 | .app-section 2 | .tabs-section 3 | .tab.css 4 | %h2 css 5 | .tab.sass 6 | %h2 sass / scss 7 | .code-section 8 | %form{:method => "POST", :action => "/", :id => "page"} 9 | .code-container.left 10 | %label{:for => "page_css"} 11 | CSS (paste your CSS code and convert!) 12 | .notifications 13 | - if flash[:notice] 14 | %span.notice= flash[:notice] 15 | - if flash[:error] 16 | %span.error= flash[:error] 17 | %textarea{:id => "page_css", :name => "page[css]"}=h @css || "" 18 | .code-container.right 19 | %label{:for => "page_sass"} 20 | Your Syntactically Awesome StyleSheets code 21 | %textarea{:id => "page_sass", :name => "page[sass]"}=h @output || "" 22 | .code-actions 23 | %input.button.sass{:type => "submit", :name => "commit", :value => "Convert 2 SASS"} 24 | %input.button.scss{:type => "submit", :name => "commit", :value => "Convert 2 SCSS"} -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | css2sass 2 | ======== 3 | 4 | [http://css2sass.heroku.com/](http://css2sass.heroku.com/) 5 | 6 | css2sass is a simple sinatra app which Convert CSS Snippets to Syntactically Awesome StyleSheets code. 7 | 8 | It's heavily inspired by the [html2haml app](http://html2haml.heroku.com/) 9 | 10 | ## Usage 11 | 12 | * Paste the CSS in the first box 13 | * click convert 14 | * Done! 15 | 16 | ## API 17 | 18 | json and xml. 19 | 20 | ## Testing 21 | 22 | See `test/test_css2sass.rb` 23 | 24 | ## TODO 25 | 26 | * Flash warnings TODO:! 27 | * More tests. 28 | 29 | ## Resources 30 | 31 | * [Sinatra](http://www.sinatrarb.com) 32 | * [SASS](http://sass-lang.com/) 33 | 34 | ## Note on Patches/Pull Requests 35 | 36 | Fork the project. 37 | Make your feature addition or bug fix. 38 | Add tests for it. This is important so I don’t break it in a future version unintentionally. 39 | Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) 40 | Send me a pull request. Bonus points for topic branches. 41 | 42 | ## Copyright 43 | 44 | Copyright 2009 Jose Pablo Barrantes. MIT Licence, so go for it. 45 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | builder (3.2.4) 5 | erubis (2.7.0) 6 | ffi (1.13.1) 7 | foreman (0.87.2) 8 | haml (5.2.0) 9 | temple (>= 0.8.0) 10 | tilt 11 | hpricot (0.8.6) 12 | json (2.3.1) 13 | mustermann (1.1.1) 14 | ruby2_keywords (~> 0.0.1) 15 | nio4r (2.5.4) 16 | puma (5.0.4) 17 | nio4r (~> 2.0) 18 | rack (2.2.3) 19 | rack-protection (2.1.0) 20 | rack 21 | rack-test (1.1.0) 22 | rack (>= 1.0, < 3) 23 | rb-fsevent (0.10.4) 24 | rb-inotify (0.10.1) 25 | ffi (~> 1.0) 26 | ruby2_keywords (0.0.2) 27 | ruby_parser (3.15.0) 28 | sexp_processor (~> 4.9) 29 | sass (3.7.4) 30 | sass-listen (~> 4.0.0) 31 | sass-listen (4.0.0) 32 | rb-fsevent (~> 0.9, >= 0.9.4) 33 | rb-inotify (~> 0.9, >= 0.9.7) 34 | sexp_processor (4.15.1) 35 | sinatra (2.1.0) 36 | mustermann (~> 1.0) 37 | rack (~> 2.2) 38 | rack-protection (= 2.1.0) 39 | tilt (~> 2.0) 40 | sinatra-redirect-with-flash (0.2.1) 41 | sinatra (>= 1.0.0) 42 | temple (0.8.2) 43 | tilt (2.0.10) 44 | 45 | PLATFORMS 46 | ruby 47 | 48 | DEPENDENCIES 49 | builder 50 | erubis 51 | foreman 52 | haml 53 | hpricot 54 | json 55 | puma 56 | rack-test 57 | ruby_parser 58 | sass 59 | sinatra 60 | sinatra-redirect-with-flash 61 | 62 | RUBY VERSION 63 | ruby 2.6.4p104 64 | 65 | BUNDLED WITH 66 | 2.1.4 67 | -------------------------------------------------------------------------------- /lib/css2sass/app.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'sinatra/base' 3 | 4 | module Css2sass 5 | class App < Sinatra::Base 6 | use Rack::Flash, :sweep => true 7 | enable :sessions 8 | set :show_exceptions, true if development? 9 | set :public_folder, Proc.new { settings.root + '/../../' + 'public' } 10 | set :views, Proc.new { settings.root + '/../../' + 'views' } 11 | 12 | helpers do 13 | include Rack::Utils 14 | alias_method :h, :escape_html 15 | end 16 | 17 | get "/" do 18 | haml :index 19 | end 20 | 21 | post "/*" do 22 | if params["page"] 23 | @css = params["page"]["css"] 24 | if params["commit"].eql?("Convert 2 SCSS") 25 | @output = Css2sass::Convert.new(@css).to_scss 26 | else 27 | @output = Css2sass::Convert.new(@css).to_sass 28 | end 29 | render_response 30 | end 31 | end 32 | 33 | def render_response 34 | if params[:splat].include?("json") 35 | Css2sass::Render.new(@css, @output).json 36 | elsif params[:splat].include?("xml") 37 | Css2sass::Render.new(@css, @output).xml 38 | else 39 | flash_if_successful 40 | haml :index 41 | end 42 | end 43 | 44 | def flash_if_successful 45 | if @output.class == Sass::SyntaxError 46 | flash_error 47 | else 48 | flash_notice 49 | end 50 | end 51 | 52 | # Flash lib is moronic! 53 | def flash_notice 54 | flash[:error] = '' 55 | flash[:success] = 'Creativity is a habit.' 56 | end 57 | 58 | def flash_error 59 | flash[:success] = '' 60 | flash[:error] = "Dude, nasty error! - #{@output}" 61 | @output = nil 62 | end 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /public/images/sass-icon.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 12 | 13 | 17 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /views/layout.haml: -------------------------------------------------------------------------------- 1 | %html 2 | %head 3 | %title css2sass | Convert CSS Snippets to Syntactically Awesome StyleSheets code 4 | - %w{ reset text 960 app }.each do |css| 5 | %link{ :href => "/stylesheets/#{css}.css", :rel => "stylesheet", :type => "text/css", :media => "screen", :charset => "utf-8" } 6 | %meta{ :name => 'description', :content => 'CSS2Sass | Convert CSS Snippets to Syntactically Awesome StyleSheets code' } 7 | %meta{ :name => 'keywords', :content => 'haml, ruby, html, rails, ruby on rails, Sass, SCSS' } 8 | %link{:href => "/images/favicon.ico", :rel => "shortcut icon", :type => "image/x-icon"} 9 | %link{:href => "http://fonts.googleapis.com/css?family=Montserrat:400,700", :rel => "stylesheet", :type => "text/css"} 10 | %link{:href => "http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600,700", :rel => "stylesheet", :type => "text/css"} 11 | :javascript 12 | var _gaq = _gaq || []; 13 | _gaq.push(['_setAccount', 'UA-5087606-8']); 14 | _gaq.push(['_trackPageview']); 15 | 16 | (function() { 17 | var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; 18 | ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 19 | var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); 20 | })(); 21 | %body 22 | .wrapper 23 | .top-section 24 | %header 25 | %h1 26 | css 2 sass/scss 27 | %span converter 28 | .top-info-section 29 | .version-info 30 | %a{:href => "http://sass-lang.com/"} Version 31 | = Sass.version[:string] 32 | .author-info 33 | %p 34 | %span idea & backend: 35 | %a{ :href => "http://jpablobr.com"} Jose Pablo Barrantes 36 | %span / 37 | %span design & frontend: 38 | %a{ :href => "http://hihayk.com"} Hayk 39 | = yield -------------------------------------------------------------------------------- /public/images/scss-icon.svg: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 12 | 15 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/test_css2sass.rb: -------------------------------------------------------------------------------- 1 | require_relative '../lib/css2sass' 2 | require 'minitest/autorun' 3 | require 'rack/test' 4 | require 'builder' 5 | 6 | class TestCss2sassApp < MiniTest::Unit::TestCase 7 | def setup 8 | @browser = Rack::Test::Session.new(Rack::MockSession.new(Css2sass::App)) 9 | end 10 | 11 | def test_home_says_css2sass 12 | @browser.get '/' 13 | assert @browser.last_response.ok? 14 | assert_match home_title, @browser.last_response.body 15 | end 16 | 17 | def test_html_sass_response 18 | @browser.post '/', css2sass_post 19 | @browser.last_response.body 20 | assert_match html_sass_response, @browser.last_response.body 21 | end 22 | 23 | def test_html_scss_response 24 | @browser.post '/', css2scss_post 25 | assert_match html_scss_response, @browser.last_response.body 26 | end 27 | 28 | def test_api_speak_json_with_sass 29 | @browser.post '/json', css2sass_post 30 | assert_match json_sass_response, @browser.last_response.body 31 | end 32 | 33 | def test_api_speak_json_with_scss 34 | @browser.post '/json', css2scss_post 35 | assert_match json_scss_response, @browser.last_response.body 36 | end 37 | 38 | def test_api_speak_xml_with_sass 39 | @browser.post '/xml', css2sass_post 40 | assert_match xml_sass_response, @browser.last_response.body 41 | end 42 | 43 | def test_api_speak_xml_with_scss 44 | @browser.post '/xml', css2scss_post 45 | assert_match xml_scss_response, @browser.last_response.body 46 | end 47 | 48 | def home_title 49 | '' + 50 | 'css2sass | Convert CSS Snippets to Syntactically Awesome StyleSheets code' + 51 | '' 52 | end 53 | 54 | def css2scss_post 55 | { :page => 56 | { :css => ".content-navigation { border-color: #3bbfce; color: #2b9eab; }" 57 | }, 58 | :commit => "Convert 2 SCSS" 59 | } 60 | end 61 | 62 | def css2sass_post 63 | { :page => 64 | { :css => ".content-navigation { border-color: #3bbfce; color: #2b9eab; }" 65 | }, 66 | :commit => "Convert 2 SASS" 67 | } 68 | end 69 | 70 | def json_sass_response 71 | '{"page":' + 72 | '{"css":".content-navigation { border-color: #3bbfce; color: #2b9eab; }",'+ 73 | '"sass":".content-navigation\n border-color: #3bbfce\n color: #2b9eab\n"}}' 74 | end 75 | 76 | def json_scss_response 77 | '{"page":' + 78 | '{"css":".content-navigation { border-color: #3bbfce; color: #2b9eab; }",' + 79 | '"sass":".content-navigation {\n border-color: #3bbfce;\n color: #2b9eab; }\n"}}' 80 | end 81 | 82 | def xml_sass_response 83 | "" + 84 | "" + 85 | "" + 86 | "" + 87 | "" + 88 | "" + 89 | "" + 90 | "" + 91 | "" 92 | end 93 | 94 | def xml_scss_response 95 | ""+ 96 | ""+ 97 | ""+ 98 | ""+ 99 | ""+ 100 | ""+ 101 | ""+ 102 | ""+ 103 | "" 104 | end 105 | 106 | def html_sass_response 107 | "" 110 | end 111 | 112 | def html_scss_response 113 | "" 117 | end 118 | 119 | end 120 | -------------------------------------------------------------------------------- /lib/css2sass/flash.rb: -------------------------------------------------------------------------------- 1 | module Rack 2 | class Flash 3 | # Raised when the session passed to FlashHash initialize is nil. This 4 | # is usually an indicator that session middleware is not in use. 5 | class SessionUnavailable < StandardError; end 6 | 7 | # Implements bracket accessors for storing and retrieving flash entries. 8 | class FlashHash 9 | attr_reader :flagged 10 | 11 | def initialize(store, opts={}) 12 | raise Rack::Flash::SessionUnavailable \ 13 | .new('Rack::Flash depends on session middleware.') unless store 14 | 15 | @opts = opts 16 | @store = store 17 | 18 | if accessors = @opts[:accessorize] 19 | accessors.each { |opt| def_accessor(opt) } 20 | end 21 | end 22 | 23 | # Remove an entry from the session and return its value. Cache result in 24 | # the instance cache. 25 | def [](key) 26 | key = key.to_sym 27 | cache[key] ||= values.delete(key) 28 | end 29 | 30 | # Store the entry in the session, updating the instance cache as well. 31 | def []=(key,val) 32 | key = key.to_sym 33 | cache[key] = values[key] = val 34 | end 35 | 36 | # Store a flash entry for only the current request, swept regardless of 37 | # whether or not it was actually accessed. Useful for AJAX requests, where 38 | # you want a flash message, even though you're response isn't redirecting. 39 | def now 40 | cache 41 | end 42 | 43 | # Checks for the presence of a flash entry without retrieving or removing 44 | # it from the cache or store. 45 | def has?(key) 46 | [cache, values].any? { |store| store.keys.include?(key.to_sym) } 47 | end 48 | alias_method :include?, :has? 49 | 50 | # Mark existing entries to allow for sweeping. 51 | def flag! 52 | @flagged = values.keys 53 | end 54 | 55 | # Remove flagged entries from flash session, clear flagged list. 56 | def sweep! 57 | Array(flagged).each { |key| values.delete(key) } 58 | flagged.clear 59 | end 60 | 61 | # Hide the underlying :__FLASH__ session key and only expose values stored 62 | # in the flash. 63 | def inspect 64 | '#' % [values.inspect, cache.inspect] 65 | end 66 | 67 | # Human readable for logging. 68 | def to_s 69 | values.inspect 70 | end 71 | 72 | private 73 | 74 | # Maintain an instance-level cache of retrieved flash entries. These 75 | # entries will have been removed from the session, but are still available 76 | # through the cache. 77 | def cache 78 | @cache ||= {} 79 | end 80 | 81 | # Helper to access flash entries from :__FLASH__ session value. This key 82 | # is used to prevent collisions with other user-defined session values. 83 | def values 84 | @store[:__FLASH__] ||= {} 85 | end 86 | 87 | # Generate accessor methods for the given entry key if :accessorize is true. 88 | def def_accessor(key) 89 | raise ArgumentError.new('Invalid entry type: %s' % key) if respond_to?(key) 90 | 91 | class << self; self end.class_eval do 92 | define_method(key) { |*args| val = args.first; val ? (self[key]=val) : self[key] } 93 | define_method("#{key}=") { |val| self[key] = val } 94 | define_method("#{key}!") { |val| cache[key] = val } 95 | end 96 | end 97 | end 98 | 99 | # ------------------------------------------------------------------------- 100 | # - Rack Middleware implementation 101 | 102 | def initialize(app, opts={}) 103 | if klass = app_class(app, opts) 104 | klass.class_eval do 105 | def flash; env['x-rack.flash'] end 106 | end 107 | end 108 | 109 | @app, @opts = app, opts 110 | end 111 | 112 | def call(env) 113 | env['x-rack.flash'] ||= Rack::Flash::FlashHash.new(env['rack.session'], @opts) 114 | 115 | if @opts[:sweep] 116 | env['x-rack.flash'].flag! 117 | end 118 | 119 | res = @app.call(env) 120 | 121 | if @opts[:sweep] 122 | env['x-rack.flash'].sweep! 123 | end 124 | 125 | res 126 | end 127 | 128 | private 129 | 130 | def app_class(app, opts) 131 | return nil if opts.has_key?(:helper) and not opts[:helper] 132 | opts[:flash_app_class] || 133 | defined?(Sinatra::Base) && Sinatra::Base || 134 | self.class.rack_builder.leaf_app.class 135 | end 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /public/stylesheets/app.css: -------------------------------------------------------------------------------- 1 | ::-moz-selection{ 2 | background-color: black; 3 | color: #3fa9f5; 4 | } 5 | ::selection{ 6 | background-color: black; 7 | color: #3fa9f5; 8 | } 9 | html{ 10 | height: 100%; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | } 14 | body { 15 | margin: 0; 16 | font-family: "Source Code Pro", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 17 | font-size: 12px; 18 | height: 100%; 19 | } 20 | a{ 21 | color: inherit; 22 | text-decoration: none; 23 | border-bottom: 1px solid #ccc; 24 | padding-bottom: 4px; 25 | -webkit-transition: all 0.3s ease; 26 | -moz-transition: all 0.3s ease; 27 | transition: all 0.3s ease; 28 | } 29 | a:hover{ 30 | color: #3fa9f5; 31 | border-bottom: 1px solid #3fa9f5; 32 | } 33 | .wrapper{ 34 | height: 100%; 35 | width: 100%; 36 | display: table; 37 | overflow: hidden; 38 | } 39 | .top-section{ 40 | padding: 30px 0 20px; 41 | display: table-row; 42 | float: left; 43 | width: 100%; 44 | } 45 | header{ 46 | border-bottom: 1px solid #e6e6e6; 47 | margin: 0 30px 10px; 48 | } 49 | h1{ 50 | font-family: montserrat; 51 | font-size: 18px; 52 | text-transform: uppercase; 53 | color: #3fa9f5; 54 | font-weight: normal; 55 | } 56 | h1 span{ 57 | color: #333; 58 | } 59 | .top-info-section{ 60 | margin-bottom: 20px; 61 | color: #666; 62 | padding: 0 30px; 63 | } 64 | .version-info{ 65 | float: left; 66 | } 67 | .author-info{ 68 | float: right; 69 | } 70 | .author-info p{ 71 | margin-bottom: 0; 72 | } 73 | .app-section{ 74 | width: 100%; 75 | height: 100%; 76 | display: table-row; 77 | } 78 | .tabs-section{ 79 | background-color: #e6e6e6; 80 | float: left; 81 | width: 100%; 82 | } 83 | .tab{ 84 | float: left; 85 | position: relative; 86 | } 87 | .tab.css{ 88 | width: 50%; 89 | } 90 | .tab.css:after{ 91 | content: ""; 92 | position: absolute; 93 | width: 1px; 94 | height: 100%; 95 | right: 0; 96 | top: 0; 97 | background-color: #ccc; 98 | } 99 | .tab.sass, 100 | .tab.scss 101 | { 102 | width: 25%; 103 | } 104 | .tab h2{ 105 | font-family: montserrat; 106 | font-weight: normal; 107 | text-transform: uppercase; 108 | font-size: 18px; 109 | padding: 11px 30px; 110 | margin: 0; 111 | } 112 | .code-section{ 113 | position: relative; 114 | background-color: #333; 115 | float: left; 116 | width: 100%; 117 | max-height: 100%; 118 | height: 100%; 119 | } 120 | .code-container.left:after{ 121 | content: ""; 122 | position: absolute; 123 | width: 1px; 124 | height: 100%; 125 | right: 0; 126 | top: 0; 127 | background-color: #252525; 128 | } 129 | .code-container.right textarea{ 130 | -webkit-animation: highlight 1s; 131 | animation: highlight 1s; 132 | } 133 | @-webkit-keyframes highlight { 134 | from {color: #3fa9f5;} 135 | to {color: #eee;} 136 | } 137 | @keyframes highlight { 138 | from {color: #3fa9f5;} 139 | to {color: #eee;} 140 | } 141 | .code-container{ 142 | width: 50%; 143 | float: left; 144 | height: 100%; 145 | position: relative; 146 | } 147 | .code-container label{ 148 | position: absolute; 149 | top: 0; 150 | padding: 20px 30px; 151 | font-size: 14px; 152 | color: #999; 153 | background-color: #333; 154 | width: 100%; 155 | } 156 | .code-container textarea{ 157 | width: 100%; 158 | height: 100%; 159 | padding: 60px 30px 80px 30px; 160 | font-family: inherit; 161 | font-size: 14px; 162 | color: #eee; 163 | background: none; 164 | border: 0; 165 | -webkit-font-smoothing: antialiased; 166 | -moz-osx-font-smoothing: grayscale; 167 | } 168 | .code-actions{ 169 | width: 50px; 170 | height: 50px; 171 | position: absolute; 172 | background-color: #3fa9f5; 173 | background-image: url("/images/conv-arr.svg"); 174 | background-size: 22px; 175 | background-repeat: no-repeat; 176 | background-position: center center; 177 | left: 0; 178 | right: 0; 179 | top: -45px; 180 | bottom: 0; 181 | margin: auto; 182 | border-radius: 50%; 183 | text-align: center; 184 | -webkit-transition: all 0.3s ease; 185 | -moz-transition: all 0.3s ease; 186 | transition: all 0.3s ease; 187 | } 188 | .code-actions:hover{ 189 | width: 110px; 190 | height: 110px; 191 | background-position: 120px center; 192 | } 193 | .code-actions .button{ 194 | background: transparent; 195 | overflow: hidden; 196 | cursor: pointer; 197 | color: transparent; 198 | font-family: montserrat; 199 | font-weight: normal; 200 | border: 0; 201 | opacity: 0; 202 | font-size: 16px; 203 | width: 100%; 204 | height: 50%; 205 | position: absolute; 206 | left: 0; 207 | right: 0; 208 | margin: 0; 209 | background-repeat: no-repeat; 210 | -webkit-transition: all 0.3s ease; 211 | -moz-transition: all 0.3s ease; 212 | transition: all 0.3s ease; 213 | } 214 | .button.scss{ 215 | border-bottom-right-radius: 55px; 216 | border-bottom-left-radius: 55px; 217 | background-image: url("/images/scss-icon.svg"); 218 | background-position: center 20px; 219 | } 220 | .button.sass{ 221 | border-top-right-radius: 55px; 222 | border-top-left-radius: 55px; 223 | background-image: url("/images/sass-icon.svg"); 224 | background-position: center bottom 20px; 225 | } 226 | .code-actions .button:hover{ 227 | background-color: #1782cf; 228 | } 229 | .code-actions .button.scss{ 230 | bottom: 0; 231 | } 232 | .code-actions .button.sass{ 233 | top: 0; 234 | } 235 | .code-actions:hover .button{ 236 | opacity: 1; 237 | } 238 | .code-actions:hover .arrow svg{ 239 | margin-left: 120px; 240 | opacity: 0; 241 | } 242 | .notifications{ 243 | position: absolute; 244 | top: 15px; 245 | left: 0; 246 | width: 99%; 247 | margin: auto; 248 | z-index: 2; 249 | padding: 0; 250 | height: auto; 251 | font-size: 14px; 252 | } 253 | .notifications span{ 254 | padding: 0 10px; 255 | background-color: #333; 256 | float: left; 257 | padding-left: 30px; 258 | padding-right: 30px; 259 | } 260 | .notice{ 261 | color: orange; 262 | } 263 | .error{ 264 | color: #FF7B7B; 265 | } 266 | .success{ 267 | color: green; 268 | } 269 | -------------------------------------------------------------------------------- /public/stylesheets/960.css: -------------------------------------------------------------------------------- 1 | .container_12,.container_16 { 2 | margin-left: auto; 3 | margin-right: auto; 4 | width: 960px 5 | } 6 | .grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12,.grid_13,.grid_14,.grid_15,.grid_16 { 7 | display: inline; 8 | float: left; 9 | position: relative; 10 | margin-left: 10px; 11 | margin-right: 10px 12 | } 13 | .container_12 .grid_3,.container_16 .grid_4 { 14 | width: 220px 15 | } 16 | .container_12 .grid_6,.container_16 .grid_8 { 17 | width: 460px 18 | } 19 | .container_12 .grid_9,.container_16 .grid_12 { 20 | width: 700px 21 | } 22 | .container_12 .grid_12,.container_16 .grid_16 { 23 | width: 940px 24 | } 25 | .alpha { 26 | margin-left: 0 27 | } 28 | .omega { 29 | margin-right: 0 30 | } 31 | .container_12 .grid_1 { 32 | width: 60px 33 | } 34 | .container_12 .grid_2 { 35 | width: 140px 36 | } 37 | .container_12 .grid_4 { 38 | width: 300px 39 | } 40 | .container_12 .grid_5 { 41 | width: 380px 42 | } 43 | .container_12 .grid_7 { 44 | width: 540px 45 | } 46 | .container_12 .grid_8 { 47 | width: 620px 48 | } 49 | .container_12 .grid_10 { 50 | width: 780px 51 | } 52 | .container_12 .grid_11 { 53 | width: 860px 54 | } 55 | .container_16 .grid_1 { 56 | width: 40px 57 | } 58 | .container_16 .grid_2 { 59 | width: 100px 60 | } 61 | .container_16 .grid_3 { 62 | width: 160px 63 | } 64 | .container_16 .grid_5 { 65 | width: 280px 66 | } 67 | .container_16 .grid_6 { 68 | width: 340px 69 | } 70 | .container_16 .grid_7 { 71 | width: 400px 72 | } 73 | .container_16 .grid_9 { 74 | width: 520px 75 | } 76 | .container_16 .grid_10 { 77 | width: 580px 78 | } 79 | .container_16 .grid_11 { 80 | width: 640px 81 | } 82 | .container_16 .grid_13 { 83 | width: 760px 84 | } 85 | .container_16 .grid_14 { 86 | width: 820px 87 | } 88 | .container_16 .grid_15 { 89 | width: 880px 90 | } 91 | .container_12 .prefix_3,.container_16 .prefix_4 { 92 | padding-left: 240px 93 | } 94 | .container_12 .prefix_6,.container_16 .prefix_8 { 95 | padding-left: 480px 96 | } 97 | .container_12 .prefix_9,.container_16 .prefix_12 { 98 | padding-left: 720px 99 | } 100 | .container_12 .prefix_1 { 101 | padding-left: 80px 102 | } 103 | .container_12 .prefix_2 { 104 | padding-left: 160px 105 | } 106 | .container_12 .prefix_4 { 107 | padding-left: 320px 108 | } 109 | .container_12 .prefix_5 { 110 | padding-left: 400px 111 | } 112 | .container_12 .prefix_7 { 113 | padding-left: 560px 114 | } 115 | .container_12 .prefix_8 { 116 | padding-left: 640px 117 | } 118 | .container_12 .prefix_10 { 119 | padding-left: 800px 120 | } 121 | .container_12 .prefix_11 { 122 | padding-left: 880px 123 | } 124 | .container_16 .prefix_1 { 125 | padding-left: 60px 126 | } 127 | .container_16 .prefix_2 { 128 | padding-left: 120px 129 | } 130 | .container_16 .prefix_3 { 131 | padding-left: 180px 132 | } 133 | .container_16 .prefix_5 { 134 | padding-left: 300px 135 | } 136 | .container_16 .prefix_6 { 137 | padding-left: 360px 138 | } 139 | .container_16 .prefix_7 { 140 | padding-left: 420px 141 | } 142 | .container_16 .prefix_9 { 143 | padding-left: 540px 144 | } 145 | .container_16 .prefix_10 { 146 | padding-left: 600px 147 | } 148 | .container_16 .prefix_11 { 149 | padding-left: 660px 150 | } 151 | .container_16 .prefix_13 { 152 | padding-left: 780px 153 | } 154 | .container_16 .prefix_14 { 155 | padding-left: 840px 156 | } 157 | .container_16 .prefix_15 { 158 | padding-left: 900px 159 | } 160 | .container_12 .suffix_3,.container_16 .suffix_4 { 161 | padding-right: 240px 162 | } 163 | .container_12 .suffix_6,.container_16 .suffix_8 { 164 | padding-right: 480px 165 | } 166 | .container_12 .suffix_9,.container_16 .suffix_12 { 167 | padding-right: 720px 168 | } 169 | .container_12 .suffix_1 { 170 | padding-right: 80px 171 | } 172 | .container_12 .suffix_2 { 173 | padding-right: 160px 174 | } 175 | .container_12 .suffix_4 { 176 | padding-right: 320px 177 | } 178 | .container_12 .suffix_5 { 179 | padding-right: 400px 180 | } 181 | .container_12 .suffix_7 { 182 | padding-right: 560px 183 | } 184 | .container_12 .suffix_8 { 185 | padding-right: 640px 186 | } 187 | .container_12 .suffix_10 { 188 | padding-right: 800px 189 | } 190 | .container_12 .suffix_11 { 191 | padding-right: 880px 192 | } 193 | .container_16 .suffix_1 { 194 | padding-right: 60px 195 | } 196 | .container_16 .suffix_2 { 197 | padding-right: 120px 198 | } 199 | .container_16 .suffix_3 { 200 | padding-right: 180px 201 | } 202 | .container_16 .suffix_5 { 203 | padding-right: 300px 204 | } 205 | .container_16 .suffix_6 { 206 | padding-right: 360px 207 | } 208 | .container_16 .suffix_7 { 209 | padding-right: 420px 210 | } 211 | .container_16 .suffix_9 { 212 | padding-right: 540px 213 | } 214 | .container_16 .suffix_10 { 215 | padding-right: 600px 216 | } 217 | .container_16 .suffix_11 { 218 | padding-right: 660px 219 | } 220 | .container_16 .suffix_13 { 221 | padding-right: 780px 222 | } 223 | .container_16 .suffix_14 { 224 | padding-right: 840px 225 | } 226 | .container_16 .suffix_15 { 227 | padding-right: 900px 228 | } 229 | .container_12 .push_3,.container_16 .push_4 { 230 | left: 240px 231 | } 232 | .container_12 .push_6,.container_16 .push_8 { 233 | left: 480px 234 | } 235 | .container_12 .push_9,.container_16 .push_12 { 236 | left: 720px 237 | } 238 | .container_12 .push_1 { 239 | left: 80px 240 | } 241 | .container_12 .push_2 { 242 | left: 160px 243 | } 244 | .container_12 .push_4 { 245 | left: 320px 246 | } 247 | .container_12 .push_5 { 248 | left: 400px 249 | } 250 | .container_12 .push_7 { 251 | left: 560px 252 | } 253 | .container_12 .push_8 { 254 | left: 640px 255 | } 256 | .container_12 .push_10 { 257 | left: 800px 258 | } 259 | .container_12 .push_11 { 260 | left: 880px 261 | } 262 | .container_16 .push_1 { 263 | left: 60px 264 | } 265 | .container_16 .push_2 { 266 | left: 120px 267 | } 268 | .container_16 .push_3 { 269 | left: 180px 270 | } 271 | .container_16 .push_5 { 272 | left: 300px 273 | } 274 | .container_16 .push_6 { 275 | left: 360px 276 | } 277 | .container_16 .push_7 { 278 | left: 420px 279 | } 280 | .container_16 .push_9 { 281 | left: 540px 282 | } 283 | .container_16 .push_10 { 284 | left: 600px 285 | } 286 | .container_16 .push_11 { 287 | left: 660px 288 | } 289 | .container_16 .push_13 { 290 | left: 780px 291 | } 292 | .container_16 .push_14 { 293 | left: 840px 294 | } 295 | .container_16 .push_15 { 296 | left: 900px 297 | } 298 | .container_12 .pull_3,.container_16 .pull_4 { 299 | left: -240px 300 | } 301 | .container_12 .pull_6,.container_16 .pull_8 { 302 | left: -480px 303 | } 304 | .container_12 .pull_9,.container_16 .pull_12 { 305 | left: -720px 306 | } 307 | .container_12 .pull_1 { 308 | left: -80px 309 | } 310 | .container_12 .pull_2 { 311 | left: -160px 312 | } 313 | .container_12 .pull_4 { 314 | left: -320px 315 | } 316 | .container_12 .pull_5 { 317 | left: -400px 318 | } 319 | .container_12 .pull_7 { 320 | left: -560px 321 | } 322 | .container_12 .pull_8 { 323 | left: -640px 324 | } 325 | .container_12 .pull_10 { 326 | left: -800px 327 | } 328 | .container_12 .pull_11 { 329 | left: -880px 330 | } 331 | .container_16 .pull_1 { 332 | left: -60px 333 | } 334 | .container_16 .pull_2 { 335 | left: -120px 336 | } 337 | .container_16 .pull_3 { 338 | left: -180px 339 | } 340 | .container_16 .pull_5 { 341 | left: -300px 342 | } 343 | .container_16 .pull_6 { 344 | left: -360px 345 | } 346 | .container_16 .pull_7 { 347 | left: -420px 348 | } 349 | .container_16 .pull_9 { 350 | left: -540px 351 | } 352 | .container_16 .pull_10 { 353 | left: -600px 354 | } 355 | .container_16 .pull_11 { 356 | left: -660px 357 | } 358 | .container_16 .pull_13 { 359 | left: -780px 360 | } 361 | .container_16 .pull_14 { 362 | left: -840px 363 | } 364 | .container_16 .pull_15 { 365 | left: -900px 366 | } 367 | .clear { 368 | clear: both; 369 | display: block; 370 | overflow: hidden; 371 | visibility: hidden; 372 | width: 0; 373 | height: 0 374 | } 375 | .clearfix:after { 376 | clear: both; 377 | content: ' '; 378 | display: block; 379 | font-size: 0; 380 | line-height: 0; 381 | visibility: hidden; 382 | width: 0; 383 | height: 0 384 | } 385 | * html .clearfix { 386 | height: 1% 387 | } 388 | --------------------------------------------------------------------------------