From 4b169b02fb1c2b699548345a1db38634119e937c Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 11 Oct 2012 12:30:08 -0700 Subject: [PATCH] Initial Commit --- .gitignore | 31 +-- Gemfile | 30 +++ Gemfile.lock | 138 +++++++++++ Procfile | 1 + README.md | 4 - README.rdoc | 66 +++++ Rakefile | 7 + app/assets/images/1-background.png | Bin 0 -> 11054 bytes app/assets/images/2-background.png | Bin 0 -> 11054 bytes app/assets/images/3-background.png | Bin 0 -> 11054 bytes app/assets/images/4-background.png | Bin 0 -> 11054 bytes app/assets/images/background.png | Bin 0 -> 11054 bytes app/assets/images/bullet.png | Bin 0 -> 148 bytes app/assets/images/rails.png | Bin 0 -> 6646 bytes app/assets/javascripts/application.js | 19 ++ app/assets/javascripts/jquery.details.js | 6 + app/assets/javascripts/jquery.textchange.js | 10 + app/assets/javascripts/preorder.js.coffee | 28 +++ app/assets/stylesheets/application.css | 14 ++ app/assets/stylesheets/checkout.css.scss | 48 ++++ app/assets/stylesheets/footer.css.scss | 23 ++ app/assets/stylesheets/header.css.scss | 19 ++ app/assets/stylesheets/homepage.css.scss | 33 +++ .../homepage/call_to_action.css.scss | 56 +++++ app/assets/stylesheets/homepage/faq.css.scss | 21 ++ .../stylesheets/homepage/key_points.css.scss | 50 ++++ .../homepage/other_points.css.scss | 28 +++ .../stylesheets/homepage/press.css.scss | 47 ++++ .../stylesheets/homepage/stats.css.scss | 96 ++++++++ app/assets/stylesheets/main.css.scss | 8 + app/assets/stylesheets/preorder.css.scss | 0 app/assets/stylesheets/primitives.css.scss | 232 ++++++++++++++++++ app/assets/stylesheets/reset.css | 48 ++++ app/assets/stylesheets/share.css.scss | 50 ++++ app/assets/stylesheets/variables.css.scss | 63 +++++ app/controllers/application_controller.rb | 3 + app/controllers/preorder_controller.rb | 42 ++++ app/helpers/application_helper.rb | 2 + app/helpers/preorder_helper.rb | 17 ++ app/mailers/.gitkeep | 0 app/models/.gitkeep | 0 app/models/order.rb | 68 +++++ app/models/user.rb | 4 + app/views/layouts/_footer.html.erb | 22 ++ app/views/layouts/application.html.erb | 14 ++ app/views/preorder/_copyright.html.erb | 1 + app/views/preorder/_footer.html.erb | 6 + app/views/preorder/_google_analytics.html.erb | 13 + app/views/preorder/_header.html.erb | 5 + app/views/preorder/checkout.html.erb | 20 ++ app/views/preorder/checkout/_sidebar.html.erb | 6 + app/views/preorder/homepage/_faqs.html.erb | 71 ++++++ .../preorder/homepage/_key_points.html.erb | 51 ++++ .../homepage/_middle_reserve.html.erb | 6 + .../preorder/homepage/_other_points.html.erb | 20 ++ app/views/preorder/homepage/_press.html.erb | 8 + .../homepage/_show_dont_tell.html.erb | 4 + app/views/preorder/homepage/_stats.html.erb | 53 ++++ .../homepage/_value_proposition.html.erb | 3 + app/views/preorder/index.html.erb | 6 + app/views/preorder/share.html.erb | 26 ++ .../preorder/share/_facebook_js.html.erb | 8 + app/views/preorder/share/_twitter_js.html.erb | 1 + config.ru | 4 + config/application.rb | 24 ++ config/boot.rb | 6 + config/database.yml | 25 ++ config/environment.rb | 5 + config/environments/development.rb | 37 +++ config/environments/production.rb | 67 +++++ config/environments/test.rb | 37 +++ .../initializers/amazon_flexible_payments.rb | 3 + config/initializers/backtrace_silencers.rb | 7 + config/initializers/inflections.rb | 15 ++ config/initializers/mime_types.rb | 5 + config/initializers/rails_config.rb | 3 + config/initializers/secret_token.rb | 7 + config/initializers/session_store.rb | 8 + config/initializers/wrap_parameters.rb | 14 ++ config/locales/en.yml | 5 + config/routes.rb | 11 + config/settings.yml | 80 ++++++ config/settings/development.yml | 0 config/settings/production.yml | 0 config/settings/test.yml | 0 db/migrate/20121004072615_create_users.rb | 9 + db/migrate/20121004072706_create_orders.rb | 26 ++ db/schema.rb | 45 ++++ db/seeds.rb | 7 + doc/README_FOR_APP | 2 + lib/assets/.gitkeep | 0 lib/tasks/.gitkeep | 0 log/.gitkeep | 0 public/404.html | 26 ++ public/422.html | 26 ++ public/500.html | 25 ++ public/favicon.ico | 0 public/robots.txt | 5 + script/rails | 6 + test/fixtures/.gitkeep | 0 test/fixtures/orders.yml | 27 ++ test/fixtures/users.yml | 7 + test/functional/.gitkeep | 0 test/functional/preorder_controller_test.rb | 19 ++ test/integration/.gitkeep | 0 test/performance/browsing_test.rb | 12 + test/test_helper.rb | 13 + test/unit/.gitkeep | 0 test/unit/helpers/preorder_helper_test.rb | 4 + test/unit/order_test.rb | 7 + test/unit/user_test.rb | 7 + vendor/assets/javascripts/.gitkeep | 0 vendor/assets/stylesheets/.gitkeep | 0 vendor/plugins/.gitkeep | 0 114 files changed, 2274 insertions(+), 18 deletions(-) create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 Procfile delete mode 100644 README.md create mode 100644 README.rdoc create mode 100644 Rakefile create mode 100644 app/assets/images/1-background.png create mode 100644 app/assets/images/2-background.png create mode 100644 app/assets/images/3-background.png create mode 100644 app/assets/images/4-background.png create mode 100644 app/assets/images/background.png create mode 100644 app/assets/images/bullet.png create mode 100644 app/assets/images/rails.png create mode 100644 app/assets/javascripts/application.js create mode 100644 app/assets/javascripts/jquery.details.js create mode 100644 app/assets/javascripts/jquery.textchange.js create mode 100644 app/assets/javascripts/preorder.js.coffee create mode 100644 app/assets/stylesheets/application.css create mode 100644 app/assets/stylesheets/checkout.css.scss create mode 100644 app/assets/stylesheets/footer.css.scss create mode 100644 app/assets/stylesheets/header.css.scss create mode 100644 app/assets/stylesheets/homepage.css.scss create mode 100644 app/assets/stylesheets/homepage/call_to_action.css.scss create mode 100644 app/assets/stylesheets/homepage/faq.css.scss create mode 100644 app/assets/stylesheets/homepage/key_points.css.scss create mode 100644 app/assets/stylesheets/homepage/other_points.css.scss create mode 100644 app/assets/stylesheets/homepage/press.css.scss create mode 100644 app/assets/stylesheets/homepage/stats.css.scss create mode 100644 app/assets/stylesheets/main.css.scss create mode 100644 app/assets/stylesheets/preorder.css.scss create mode 100644 app/assets/stylesheets/primitives.css.scss create mode 100644 app/assets/stylesheets/reset.css create mode 100644 app/assets/stylesheets/share.css.scss create mode 100644 app/assets/stylesheets/variables.css.scss create mode 100644 app/controllers/application_controller.rb create mode 100644 app/controllers/preorder_controller.rb create mode 100644 app/helpers/application_helper.rb create mode 100644 app/helpers/preorder_helper.rb create mode 100644 app/mailers/.gitkeep create mode 100644 app/models/.gitkeep create mode 100644 app/models/order.rb create mode 100644 app/models/user.rb create mode 100644 app/views/layouts/_footer.html.erb create mode 100644 app/views/layouts/application.html.erb create mode 100644 app/views/preorder/_copyright.html.erb create mode 100644 app/views/preorder/_footer.html.erb create mode 100644 app/views/preorder/_google_analytics.html.erb create mode 100644 app/views/preorder/_header.html.erb create mode 100644 app/views/preorder/checkout.html.erb create mode 100644 app/views/preorder/checkout/_sidebar.html.erb create mode 100644 app/views/preorder/homepage/_faqs.html.erb create mode 100644 app/views/preorder/homepage/_key_points.html.erb create mode 100644 app/views/preorder/homepage/_middle_reserve.html.erb create mode 100644 app/views/preorder/homepage/_other_points.html.erb create mode 100644 app/views/preorder/homepage/_press.html.erb create mode 100644 app/views/preorder/homepage/_show_dont_tell.html.erb create mode 100644 app/views/preorder/homepage/_stats.html.erb create mode 100644 app/views/preorder/homepage/_value_proposition.html.erb create mode 100644 app/views/preorder/index.html.erb create mode 100644 app/views/preorder/share.html.erb create mode 100644 app/views/preorder/share/_facebook_js.html.erb create mode 100644 app/views/preorder/share/_twitter_js.html.erb create mode 100644 config.ru create mode 100644 config/application.rb create mode 100644 config/boot.rb create mode 100644 config/database.yml create mode 100644 config/environment.rb create mode 100644 config/environments/development.rb create mode 100644 config/environments/production.rb create mode 100644 config/environments/test.rb create mode 100644 config/initializers/amazon_flexible_payments.rb create mode 100644 config/initializers/backtrace_silencers.rb create mode 100644 config/initializers/inflections.rb create mode 100644 config/initializers/mime_types.rb create mode 100644 config/initializers/rails_config.rb create mode 100644 config/initializers/secret_token.rb create mode 100644 config/initializers/session_store.rb create mode 100644 config/initializers/wrap_parameters.rb create mode 100644 config/locales/en.yml create mode 100644 config/routes.rb create mode 100644 config/settings.yml create mode 100644 config/settings/development.yml create mode 100644 config/settings/production.yml create mode 100644 config/settings/test.yml create mode 100644 db/migrate/20121004072615_create_users.rb create mode 100644 db/migrate/20121004072706_create_orders.rb create mode 100644 db/schema.rb create mode 100644 db/seeds.rb create mode 100644 doc/README_FOR_APP create mode 100644 lib/assets/.gitkeep create mode 100644 lib/tasks/.gitkeep create mode 100644 log/.gitkeep create mode 100644 public/404.html create mode 100644 public/422.html create mode 100644 public/500.html create mode 100644 public/favicon.ico create mode 100644 public/robots.txt create mode 100755 script/rails create mode 100644 test/fixtures/.gitkeep create mode 100644 test/fixtures/orders.yml create mode 100644 test/fixtures/users.yml create mode 100644 test/functional/.gitkeep create mode 100644 test/functional/preorder_controller_test.rb create mode 100644 test/integration/.gitkeep create mode 100644 test/performance/browsing_test.rb create mode 100644 test/test_helper.rb create mode 100644 test/unit/.gitkeep create mode 100644 test/unit/helpers/preorder_helper_test.rb create mode 100644 test/unit/order_test.rb create mode 100644 test/unit/user_test.rb create mode 100644 vendor/assets/javascripts/.gitkeep create mode 100644 vendor/assets/stylesheets/.gitkeep create mode 100644 vendor/plugins/.gitkeep diff --git a/.gitignore b/.gitignore index 54cb8bbbc..fd3f34b20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,19 @@ -*.rbc -*.sassc -.sass-cache -capybara-*.html -.rspec +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +# Ignore bundler config /.bundle -/vendor/bundle -/log/* -/tmp/* + +# Ignore the default SQLite database. /db/*.sqlite3 -/public/system/* -/coverage/ -/spec/tmp/* -**.orig -rerun.txt -pickle-email-*.html \ No newline at end of file + +# Ignore all logfiles and tempfiles. +/log/*.log +/tmp + +config/settings.local.yml +config/settings/*.local.yml +config/environments/*.local.yml diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..26fbd1011 --- /dev/null +++ b/Gemfile @@ -0,0 +1,30 @@ +source 'https://rubygems.org' + +gem 'rails', '3.2.8' + +group :development do + gem 'sqlite3' +end + +group :production do + gem 'thin' + gem 'pg' +end + +# Gems used only for assets and not required +# in production environments by default. +group :assets do + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + gem 'therubyracer', :platforms => :ruby + gem 'uglifier', '>= 1.0.3' +end + +# jQuery +gem 'jquery-rails' + +# Kickstarter's awesome Amazon Flexible Payments gem +gem 'amazon_flex_pay' + +# Configuration File +gem 'rails_config' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..dc4674709 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,138 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.2.8) + actionpack (= 3.2.8) + mail (~> 2.4.4) + actionpack (3.2.8) + activemodel (= 3.2.8) + activesupport (= 3.2.8) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.0) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.1.3) + activemodel (3.2.8) + activesupport (= 3.2.8) + builder (~> 3.0.0) + activerecord (3.2.8) + activemodel (= 3.2.8) + activesupport (= 3.2.8) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.8) + activemodel (= 3.2.8) + activesupport (= 3.2.8) + activesupport (3.2.8) + i18n (~> 0.6) + multi_json (~> 1.0) + amazon_flex_pay (0.9.13) + activesupport (>= 3.0.14) + multi_xml (~> 0.2.0) + rest-client (~> 1.6.1) + arel (3.0.2) + builder (3.0.3) + coffee-rails (3.2.2) + coffee-script (>= 2.2.0) + railties (~> 3.2.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.3.3) + daemons (1.1.9) + erubis (2.7.0) + eventmachine (1.0.0) + execjs (1.4.0) + multi_json (~> 1.0) + foreman (0.60.2) + thor (>= 0.13.6) + hike (1.2.1) + i18n (0.6.1) + journey (1.0.4) + jquery-rails (2.1.3) + railties (>= 3.1.0, < 5.0) + thor (~> 0.14) + json (1.7.5) + libv8 (3.3.10.4) + mail (2.4.4) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.19) + multi_json (1.3.6) + multi_xml (0.2.2) + pg (0.14.1) + polyglot (0.3.3) + rack (1.4.1) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.2) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.2.8) + actionmailer (= 3.2.8) + actionpack (= 3.2.8) + activerecord (= 3.2.8) + activeresource (= 3.2.8) + activesupport (= 3.2.8) + bundler (~> 1.0) + railties (= 3.2.8) + rails_config (0.3.1) + activesupport (>= 3.0) + railties (3.2.8) + actionpack (= 3.2.8) + activesupport (= 3.2.8) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (>= 0.14.6, < 2.0) + rake (0.9.2.2) + rdoc (3.12) + json (~> 1.4) + rest-client (1.6.7) + mime-types (>= 1.16) + sass (3.2.1) + sass-rails (3.2.5) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + sprockets (2.1.3) + hike (~> 1.2) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.6) + therubyracer (0.10.2) + libv8 (~> 3.3.10) + thin (1.5.0) + daemons (>= 1.0.9) + eventmachine (>= 0.12.6) + rack (>= 1.0.0) + thor (0.16.0) + tilt (1.3.3) + treetop (1.4.10) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.33) + uglifier (1.3.0) + execjs (>= 0.3.0) + multi_json (~> 1.0, >= 1.0.2) + +PLATFORMS + ruby + +DEPENDENCIES + amazon_flex_pay + coffee-rails (~> 3.2.1) + foreman + jquery-rails + pg + rails (= 3.2.8) + rails_config + sass-rails (~> 3.2.3) + sqlite3 + therubyracer + thin + uglifier (>= 1.0.3) diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..feb3eaa09 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: bundle exec rails server thin -p $PORT -e $RACK_ENV \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 1b8e84292..000000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -selfstarter -=========== - -Roll your own crowdfunding \ No newline at end of file diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 000000000..21fc09c57 --- /dev/null +++ b/README.rdoc @@ -0,0 +1,66 @@ +# Selfstarter +Selfstarter makes it easy to roll your own crowdfunding site. To get started, fork this repository and change around ```config/settings.yml``` to suit your needs. + +## Background + +[Kickstarter rejected us](http://techcrunch.com/2012/10/07/the-story-of-lockitron-crowdfunding-without-kickstarter/), so we made our own crowdfunding for [Lockitron](https://lockitron.com). Feel free to [give us feedback](mailto:hello@lockitron.com)! + +Over the past week, a lot of people asked us for help with building their own crowdfunding app. This is it. + +Selfstarter is starting point. We made some specific choices with Selfstarter for Lockitron and we recommend you tailor it for your project: + +* We use Amazon Payments for payments. You can use Stripe or WePay. We used Kickstarter's awesome ```amazon_flex_pay``` gem. +* We collect multi-use tokens from customers with Amazon Payments - this let's us collect payment information without charging the customer until we are ready to ship +* Selfstarter doesn't come with any authentication, administration, mailers or analytics tools. We recommend adding a basic set of these so that you can message backers and manage orders. + +## Getting Started + +First you'll need to fork and clone this repo + +Let's get all our dependencies setup: +```bash +bundle install --without production +``` + +Now let's create the database: +```bash +rake db:migrate +``` + +Let's get it running: +```bash +rails s +``` + +### Customizing + +While it is *just* a skeleton, we did make it a little quicker to change around things like your product name, the colors, pricing, etc. + +To change around the product name, tweet text, and more, open this file: + +``` +config/settings.yml +``` + +To change around the colors and fonts, open this file: + +``` +app/assets/stylesheets/variables.css.scss +``` + +To dive into the code, open this file: + +``` +app/controllers/preorder_controller.rb +``` + +### Deploying to Production + +We recommend using Heroku, and we even include a ```Procfile``` for you. All you need to do is run: + +```bash +gem install heroku +heroku create +git push heroku master +heroku run rake db:migrate +``` \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..9f0f37a0b --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +#!/usr/bin/env rake +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) + +Selfstarter::Application.load_tasks diff --git a/app/assets/images/1-background.png b/app/assets/images/1-background.png new file mode 100644 index 0000000000000000000000000000000000000000..18d4c45f366d46ac2a9c12a5a2ec8137c33d5ac1 GIT binary patch literal 11054 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 literal 0 HcmV?d00001 diff --git a/app/assets/images/rails.png b/app/assets/images/rails.png new file mode 100644 index 0000000000000000000000000000000000000000..d5edc04e65f555e3ba4dcdaad39dc352e75b575e GIT binary patch literal 6646 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 AQ~&?~ literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 000000000..c0c4ac037 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,19 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD +// GO AFTER THE REQUIRES BELOW. +// +//= require jquery +//= require jquery_ujs +//= require jquery-ui +//= require jquery.details +//= require jquery.textchange +//= require preorder +//= require_tree . diff --git a/app/assets/javascripts/jquery.details.js b/app/assets/javascripts/jquery.details.js new file mode 100644 index 000000000..631a56384 --- /dev/null +++ b/app/assets/javascripts/jquery.details.js @@ -0,0 +1,6 @@ +(function(b){var d="open"in document.createElement("details"),e;b.fn.details=function(a){"open"===a&&(d?this.prop("open",!0):this.trigger("open"));"close"===a&&(d?this.prop("open",!1):this.trigger("close"));"init"===a&&e(b(this));if(!a){if(!d)return this.hasClass("open");var c=!1;this.each(function(){if(this.open)return c=!0,!1});return c}};e=function(a){a=a.not(".details-inited").addClass("details-inited");a.filter(".animated").each(function(){var a=b(this),d=a.children("summary").remove(),e=b("
").addClass("details-wrapper").append(a.children()); +a.append(e).prepend(d)});d||(a.each(function(){var a=b(this);a.children("summary").length||a.prepend("Details")}).children("summary").filter(":not(tabindex)").attr("tabindex",0).end().end().contents(":not(summary)").filter(function(){return 3===this.nodeType&&/[^\t\n\r ]/.test(this.data)}).wrap("").end().end().filter(":not([open])").prop("open",!1).end().filter("[open]").addClass("open").prop("open",!0).end(),b.browser.msie&&9>b.browser.msie&&a.filter(":not(.open)").children().not("summary").hide())}; +b(function(){b("body").on("open.details","details.animated",function(){var a=b(this),c=a.children(".details-wrapper");c.hide();setTimeout(function(){c.slideDown(a.data("animation-speed"))},0)}).on("close.details","details.animated",function(){var a=b(this),c=a.children(".details-wrapper");setTimeout(function(){a.prop("open",!0).addClass("open");c.slideUp(a.data("animation-speed"),function(){a.prop("open",!1).removeClass("open")})},0)});if(d)b("body").on("click","summary",function(){var a=b(this).parent(); +a.prop("open")?a.trigger("close"):a.trigger("open")});else if(b("html").addClass("no-details"),b("head").prepend(''),b("body").on("open.details","details",function(a){b(this).addClass("open").trigger("change.details");a.stopPropagation()}).on("close.details","details",function(a){b(this).removeClass("open").trigger("change.details"); +a.stopPropagation()}).on("toggle.details","details",function(a){var c=b(this);c.hasClass("open")?c.trigger("close"):c.trigger("open");a.stopPropagation()}).on("click","summary",function(){b(this).parent().trigger("toggle")}).on("keyup","summary",function(a){(32===a.keyCode||13===a.keyCode&&!b.browser.opera)&&b(this).parent().trigger("toggle")}),b.browser.msie&&9>b.browser.msie)b("body").on("open.details","details",function(){b(this).children().not("summary").show()}).on("close.details","details", +function(){b(this).children().not("summary").hide()});e(b("details"))})})(jQuery); \ No newline at end of file diff --git a/app/assets/javascripts/jquery.textchange.js b/app/assets/javascripts/jquery.textchange.js new file mode 100644 index 000000000..93f179a23 --- /dev/null +++ b/app/assets/javascripts/jquery.textchange.js @@ -0,0 +1,10 @@ +/*! + * jQuery TextChange Plugin + * http://www.zurb.com/playground/jquery-text-change-custom-event + * + * Copyright 2010, ZURB + * Released under the MIT License + */ + (function(a){a.event.special.textchange={setup:function(){a(this).data("lastValue",this.contentEditable==="true"?a(this).html():a(this).val());a(this).bind("keyup.textchange",a.event.special.textchange.handler);a(this).bind("cut.textchange paste.textchange input.textchange",a.event.special.textchange.delayedHandler)},teardown:function(){a(this).unbind(".textchange")},handler:function(){a.event.special.textchange.triggerIfChanged(a(this))},delayedHandler:function(){var c=a(this);setTimeout(function(){a.event.special.textchange.triggerIfChanged(c)}, + 25)},triggerIfChanged:function(a){var b=a[0].contentEditable==="true"?a.html():a.val();b!==a.data("lastValue")&&(a.trigger("textchange",[a.data("lastValue")]),a.data("lastValue",b))}};a.event.special.hastext={setup:function(){a(this).bind("textchange",a.event.special.hastext.handler)},teardown:function(){a(this).unbind("textchange",a.event.special.hastext.handler)},handler:function(c,b){b===""&&b!==a(this).val()&&a(this).trigger("hastext")}};a.event.special.notext={setup:function(){a(this).bind("textchange", + a.event.special.notext.handler)},teardown:function(){a(this).unbind("textchange",a.event.special.notext.handler)},handler:function(c,b){a(this).val()===""&&a(this).val()!==b&&a(this).trigger("notext")}}})(jQuery); \ No newline at end of file diff --git a/app/assets/javascripts/preorder.js.coffee b/app/assets/javascripts/preorder.js.coffee new file mode 100644 index 000000000..3919e253b --- /dev/null +++ b/app/assets/javascripts/preorder.js.coffee @@ -0,0 +1,28 @@ +Selfstarter = + firstTime: true + validateEmail: -> + # The regex we use for validating email + # It probably should be a parser, but there isn't enough time for that (Maybe in the future though!) + if /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/.test($("#email").val()) + $("#email").removeClass("highlight") + $("#amazon_button").removeClass("disabled") + else + $("#email").addClass("highlight") unless Selfstarter.firstTime + $("#amazon_button").addClass("disabled") unless $("#amazon_button").hasClass("disabled") + init: -> + $("#email").bind "textchange", -> + Selfstarter.validateEmail() + $("#email").bind "hastext", -> + Selfstarter.validateEmail() + # The first time they type in their email, we don't want it to throw a validation error + $("#email").change -> + Selfstarter.firstTime = false +$ -> + Selfstarter.init() + $("#email").focus() + + + + + + diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 000000000..e19465f00 --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,14 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the top of the + * compiled file, but it's generally better to create a new file per style scope. + * + *= require_self + *= require reset + *= require main + */ diff --git a/app/assets/stylesheets/checkout.css.scss b/app/assets/stylesheets/checkout.css.scss new file mode 100644 index 000000000..9f9946dfb --- /dev/null +++ b/app/assets/stylesheets/checkout.css.scss @@ -0,0 +1,48 @@ +.main_content +{ + width: 560px; + float: left; + h3 + { + margin-bottom: 30px; + color: #4b4b4b; + line-height: 1; + } + p + { + line-height: 1.5; + } + #checkout + { + #email + { + padding: 15px; + border-radius: 10px; + border: 1px solid #CCC; + width: 350px; + outline: none; + } + .invalid + { + border: 1px solid orange; + } + #amazon_button + { + margin-top: 5px; + padding: 15px; + border: none; + } + } +} + +.sidebar +{ + float: right; + width: 300px; + p + { + font-size: 18px; + margin-bottom: 30px; + line-height: 1.3; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/footer.css.scss b/app/assets/stylesheets/footer.css.scss new file mode 100644 index 000000000..f2b465644 --- /dev/null +++ b/app/assets/stylesheets/footer.css.scss @@ -0,0 +1,23 @@ +.footer +{ + padding: 40px 0; + ul + { + float: left; + } + li + { + margin-bottom: 10px; + } + a + { + font-size: 18px; + color: #525252; + font-family: $primary_font, $secondary_font, $tertiary_font; + } + p + { + float: right; + font-size: 18px; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/header.css.scss b/app/assets/stylesheets/header.css.scss new file mode 100644 index 000000000..1774011c1 --- /dev/null +++ b/app/assets/stylesheets/header.css.scss @@ -0,0 +1,19 @@ +#lockitron_header +{ + border: none; + a + { + border: none !important; + font-size: inherit !important; + } +} +#header +{ + width: 100%; + padding: 26px 0; + -moz-box-shadow: 0px 1px 3px 0px #acacac; + -webkit-box-shadow: 0px 1px 3px 0px #acacac; + box-shadow: 0px 1px 3px 0px #acacac; + background: #fcfcfc; + position: relative; +} \ No newline at end of file diff --git a/app/assets/stylesheets/homepage.css.scss b/app/assets/stylesheets/homepage.css.scss new file mode 100644 index 000000000..a9a7f425c --- /dev/null +++ b/app/assets/stylesheets/homepage.css.scss @@ -0,0 +1,33 @@ +@import "homepage/stats"; +@import "homepage/call_to_action"; +@import "homepage/key_points"; +@import "homepage/other_points"; +@import "homepage/press"; +@import "homepage/faq"; + +#tweet_button +{ + margin-top: 5px; +} + +.fb-like +{ + margin-left: 5px; + float:left; +} + +#video +{ + float: left; + width: 512px; + height: 385px; + background: #fff; + -moz-box-shadow: 0 2px 6px rgba(0,0,0,.39); /* drop shadow */ + -webkit-box-shadow: 0 2px 6px rgba(0,0,0,.39); /* drop shadow */ + box-shadow: 0 2px 6px rgba(0,0,0,.39); /* drop shadow */ + img:hover + { + opacity: 0.5; + cursor: pointer; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/homepage/call_to_action.css.scss b/app/assets/stylesheets/homepage/call_to_action.css.scss new file mode 100644 index 000000000..edb154b69 --- /dev/null +++ b/app/assets/stylesheets/homepage/call_to_action.css.scss @@ -0,0 +1,56 @@ +#reserve_container +{ + float: left; + padding-top: 20px; + border-top: 1px solid #fff; + -moz-box-shadow: 0 -1px 0 #cbcbcb; /* drop shadow */ + -webkit-box-shadow: 0 -1px 0 #cbcbcb; /* drop shadow */ + box-shadow: 0 -1px 0 #cbcbcb; /* drop shadow */ + margin-top: 30px; + text-align: center; + p + { + color: #8b8a8a; + font-size: 18px; + line-height: 1.4; + } + #ship_date + { + color: #4c4c4c; + font-size: 22px; + font-family: $primary_font, $secondary_font, $tertiary_font; + line-height: 1.3; + display: block; + margin: 0 auto; + width: 300px; + } + #price + { + color: #4c4c4c; + font-size: 22px; + font-family: $primary_font, $secondary_font, $tertiary_font; + line-height: 1.3; + display: block; + margin: 0 auto 10px auto; + width: 300px; + } +} +.reserve +{ + margin: 0 auto; + margin-top: 20px; + margin-bottom: 20px; + padding: 20px 0; + width: 274px; + font-size: 32px; +} + +#middle_reserve +{ + padding: 60px; + h2 + { + margin-bottom: 26px; + } +} + diff --git a/app/assets/stylesheets/homepage/faq.css.scss b/app/assets/stylesheets/homepage/faq.css.scss new file mode 100644 index 000000000..ab3b8217d --- /dev/null +++ b/app/assets/stylesheets/homepage/faq.css.scss @@ -0,0 +1,21 @@ +#faqs { + padding-bottom: 30px; + border-bottom: 1px solid #dfdfdf; + ul { + margin-top: 50px; + float: left; + width: 50%; + li + { + width: 400px; + margin: 0 49px 30px 0; + padding-left: 18px; + background: url(image_path("bullet.png")) no-repeat left 8px; + p { + margin-top: 10px; + line-height: 1.4; + font-size: 18px; + } + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/homepage/key_points.css.scss b/app/assets/stylesheets/homepage/key_points.css.scss new file mode 100644 index 000000000..9bded1f50 --- /dev/null +++ b/app/assets/stylesheets/homepage/key_points.css.scss @@ -0,0 +1,50 @@ +.big_wrapper { + border-bottom: 1px solid #d2d2d2; + background: #fff; +} +.big_wrapper .wrapper { + padding: 35px 0; +} + +.point_copy { + width: 440px; + h3 { + margin: 20px 0 30px 0; + } +} + +h3 { + font-size: 42px; + font-family: $primary_font, $secondary_font, $tertiary_font; + color: #292929; + line-height: 1.3; +} + +.point_copy p, #other_points li p { + line-height: 1.5; +} + +#one { + background: url(image_path("1-background.png")) no-repeat bottom left; + height: 320px; + width: 936px; +} + +#two { + background: url(image_path("2-background.png")) no-repeat bottom left; + height: 320px; +} + +#three { + background: url(image_path("3-background.png")) no-repeat bottom left; + height: 320px; +} + +#four { + background: url(image_path("4-background.png")) no-repeat bottom left; + height: 320px; +} + +.right { + margin-left: 500px; +} diff --git a/app/assets/stylesheets/homepage/other_points.css.scss b/app/assets/stylesheets/homepage/other_points.css.scss new file mode 100644 index 000000000..4471031c7 --- /dev/null +++ b/app/assets/stylesheets/homepage/other_points.css.scss @@ -0,0 +1,28 @@ +#other_points +{ + li + { + width: 400px; + float: left; + margin: 0 120px 50px 0; + padding-top: 60px; + } + #section-1 { + background: url(asset-path("", "images")) no-repeat center top; + } + #section-2 { + background: url(asset-path("", "images")) no-repeat center top; + margin-right: 0px; + } + #section-3 { + background: url(asset-path("", "images")) no-repeat center top; + } + #section-4 { + background: url(asset-path("", "images")) no-repeat center top; + margin-right: 0px; + } + h4 { + width: 400px; + text-align: center; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/homepage/press.css.scss b/app/assets/stylesheets/homepage/press.css.scss new file mode 100644 index 000000000..c18b38e78 --- /dev/null +++ b/app/assets/stylesheets/homepage/press.css.scss @@ -0,0 +1,47 @@ +#logos { + padding: 40px 0; + background: #f3f3f3; + -moz-box-shadow: 0px 1px 3px 0px #acacac; + -webkit-box-shadow: 0px 1px 3px 0px #acacac; + box-shadow: 0px 1px 3px 0px #acacac; + li + { + float: left; + margin: 0 16px; + a { + display: block; + height: 48px; + opacity: 0.2; + text-indent: -10000px; + } + a:hover { + opacity: 1; + } + } + #awesomeblog a + { + background: url(image-path("")) no-repeat left center; + width: 176px; + } + #coolpaper a + { + background: url(image-path("")) no-repeat left center; + width: 109px; + } + #nicemag a + { + background: url(image-path("")) no-repeat left center; + width: 149px; + } + #readcrunch a + { + background: url(image-path("")) no-repeat left center; + width: 81px; + } +} + + + + + + diff --git a/app/assets/stylesheets/homepage/stats.css.scss b/app/assets/stylesheets/homepage/stats.css.scss new file mode 100644 index 000000000..42d16b351 --- /dev/null +++ b/app/assets/stylesheets/homepage/stats.css.scss @@ -0,0 +1,96 @@ +#backing +{ + float: left; + width: 383px; + margin: 20px 0 0 40px; + #backers + { + border-left: none; + padding-left: 0; + ul + { + float: left; + } + } + #days { + border-right: none; + padding-right: 0; + } + ul { + text-align: center; + } + .stats + { + margin: 0 auto; + color: #3f3f3f; + font-size: 24px; + display: block; + display: inline-block; + font-family: $primary_font, $secondary_font, $tertiary_font; + border-right: 1px solid #cbcbcb; + padding-right: 26px; + padding-left: 26px; + text-align: left; + span + { + color: #868686; + font-size: 18px; + margin-top: 5px; + display: block; + font-family: $primary_font, $secondary_font, $tertiary_font; + } + } +} +#progress_bg +{ + margin-top: 20px; + float: left; + height: 40px; + -moz-box-shadow: 0 1px 1px rgba(0,0,0,.41); /* drop shadow */ + -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.41); /* drop shadow */ + box-shadow: 0 1px 1px rgba(0,0,0,.41); /* drop shadow */ + -webkit-border-radius: 30px; + -moz-border-radius: 30px; + border-radius: 30px; + width: 383px; + background: #dbdbdb; + #progress + { + height: 40px; + -moz-box-shadow: 0 1px 1px rgba(0,0,0,.59); /* drop shadow */ + -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.59); /* drop shadow */ + box-shadow: 0 1px 1px rgba(0,0,0,.59); /* drop shadow */ + background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGxpbmVhckdyYWRpZW50IGlkPSJoYXQwIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjEwMCUiIHgyPSI1MCUiIHkyPSIwJSI+CjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMxMzkyZGMiIHN0b3Atb3BhY2l0eT0iMSIvPgo8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwNjlkZjQiIHN0b3Atb3BhY2l0eT0iMSIvPgogICA8L2xpbmVhckdyYWRpZW50PgoKPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNoYXQwKSIgLz4KPC9zdmc+); /* gradient fill */ + background-image: -moz-linear-gradient(90deg, #1392dc 0%, #069df4 100%); /* gradient fill */ + background-image: -o-linear-gradient(90deg, #1392dc 0%, #069df4 100%); /* gradient fill */ + background-image: -webkit-linear-gradient(90deg, #1392dc 0%, #069df4 100%); /* gradient fill */ + background-image: linear-gradient(90deg, #1392dc 0%, #069df4 100%); /* gradient fill */ + -webkit-border-radius: 30px; + -moz-border-radius: 30px; + border-radius: 30px; + min-width: 2%; + width: 100%; + max-width: 100%; + display: inline-block; + } + #progress_text + { + margin: 0 auto; + width: 100%; + font-size: 14pt; + display: inline-block; + color: white; + text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.37); + text-align: center; + position: relative; + top: -35px; + } +} +.small +{ + height: 20px !important; + #progress + { + height: 20px !important; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/main.css.scss b/app/assets/stylesheets/main.css.scss new file mode 100644 index 000000000..2fc6ba1b5 --- /dev/null +++ b/app/assets/stylesheets/main.css.scss @@ -0,0 +1,8 @@ +@import "variables"; +@import "primitives"; +@import "header"; +@import "footer"; + +@import "homepage"; +@import "share"; +@import "checkout"; \ No newline at end of file diff --git a/app/assets/stylesheets/preorder.css.scss b/app/assets/stylesheets/preorder.css.scss new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/stylesheets/primitives.css.scss b/app/assets/stylesheets/primitives.css.scss new file mode 100644 index 000000000..37bab10b1 --- /dev/null +++ b/app/assets/stylesheets/primitives.css.scss @@ -0,0 +1,232 @@ + +/* For modern browsers */ +.clearfix:before, +.clearfix:after +{ + content:""; + display:table; +} +.clearfix:after +{ + clear:both; +} +/* For IE 6/7 (trigger hasLayout) */ +.clearfix { + zoom:1; +} + + code + { + border: 1px solid #CCC; + padding: 1px; + vertical-align: middle; + font-family: "Consolas", "Inconsolata", "Meslo", "Inconsolata-dz", monospace; + text-shadow: none; + font-size: 10pt; + } + +html, body { + width: 100%; +} + +body { + background: $body_background; +} + +.disabled +{ + opacity: 0.65; + pointer-events: none; +} + +form +{ + margin-top: 15px; +} + +body, input, textarea +{ + font-size: $font_size; + font-family: $primary_font, $secondary_font, $tertiary_font; + color: $text_color; + text-shadow: $text_shadow; + -webkit-font-smoothing: antialiased; +} + +a +{ + text-decoration: none; + color: $link_color; +} + +a:hover +{ + text-decoration: underline; +} + +i +{ + font-style: italic; +} + + + + +// Used in the FAQ +details, summary +{ + outline: none; +} +summary +{ + text-decoration: none; + color: $summary_color; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + font-size: 20px; + line-height: 1.3; + +} +summary:hover +{ + text-decoration: underline; + cursor: pointer; +} +details summary::-webkit-details-marker { display:none; content: ""; } +// Styling the polyfill for browsers that don't support details/summary tags +.no-details details { display: block } +.no-details details > summary::before { content:none } +.no-details details.open > summary::before { content:none } + + + +h1 { + margin: 0 auto; + margin-left: 380px; + width: 174px; + font-family: Helvetica; + font-size: 42px; + font-weight: bold; + color: $h1_color; + letter-spacing: -.05em; + float: left; + a + { + color: $h1_color; + text-decoration: none; + } + a:hover + { + color: $h1_color; + text-decoration: none; + } +} + +h2 { + font-family: $primary_font, $secondary_font, $tertiary_font; + font-size: 45px; + color: $h2_color; + margin-bottom: 50px; +} + +h4 { + font-size: 36px; + color: $h4_color; + margin-bottom: 30px; +} + +h5 { + font-family: $primary_font, $secondary_font, $tertiary_font; + margin-bottom: 10px; + color: $h5_color; +} + +.wrapper { + width: 935px; + margin: 0 auto; +} + +.center { + text-align: center; +} + +.gray_background +{ + width: 100%; + padding: 50px 0; + background: $gray_background_top_color; /* Old browsers */ + background: -moz-linear-gradient(top, $gray_background_top_color 0%, $gray_background_middle_color 50%, $gray_background_bottom_color 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$gray_background_top_color), color-stop(50%,$gray_background_middle_color), color-stop(100%,$gray_background_bottom_color)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, $gray_background_top_color 0%,$gray_background_middle_color 50%,$gray_background_bottom_color 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, $gray_background_top_color 0%,$gray_background_middle_color 50%,$gray_background_bottom_color 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, $gray_background_top_color 0%,$gray_background_middle_color 50%,$gray_background_bottom_color 100%); /* IE10+ */ + background: linear-gradient(to bottom, $gray_background_top_color 0%,$gray_background_middle_color 50%,$gray_background_bottom_color 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='$gray_background_top_color', endColorstr='$gray_background_bottom_color',GradientType=0 ); /* IE6-9 */ + border-bottom: 1px solid $gray_background_border_color; +} + +.button:hover { + text-decoration: none; + color: $button_hovered_color; +} + +.button:active { + background: $button_active_background; + border: 1px solid $button_active_border; +} + +.blue_button { + display: block; + color: $button_color; /* text color */ + text-shadow: 0 -1px 1px $button-text_shadow_color; /* drop shadow */ + -moz-box-shadow: + 0 1px 1px $button_box_shadow_color /* drop shadow */, + inset 0 -1px $button_box_shadow_inset_color /* inner shadow */; + -webkit-box-shadow: + 0 1px 1px $button_box_shadow_color /* drop shadow */, + inset 0 -1px 1px $button_box_shadow_inset_color /* inner shadow */; + background-image: $button_top_gradient; /* gradient fill */ + background-image: -moz-linear-gradient(90deg, $button_top_gradient 0%, $button_bottom_gradient 100%); /* gradient fill */ + background-image: -o-linear-gradient(90deg, $button_top_gradient 0%, $button_bottom_gradient 100%); /* gradient fill */ + background-image: -webkit-linear-gradient(90deg, $button_top_gradient 0%, $button_bottom_gradient 100%); /* gradient fill */ + background-image: linear-gradient(90deg, $button_top_gradient 0%, $button_bottom_gradient 100%); /* gradient fill */ + -webkit-border-radius: $button_border_radius; + -moz-border-radius: $button_border_radius; + border-radius: $button_border_radius; + font-family: $primary_font, $secondary_font, $tertiary_font; +} +.blue_button:hover { + -moz-box-shadow: + 0 1px 1px $button_box_shadow_color /* drop shadow */, + inset 0 -1px 1px $button_box_shadow_inset_color /* inner shadow */; + -webkit-box-shadow: + 0 1px 1px$button_box_shadow_color /* drop shadow */, + inset 0 -1px 1px $button_box_shadow_inset_color /* inner shadow */; + box-shadow: + 0 1px 1px $button_box_shadow_color /* drop shadow */, + inset 0 -1px 1px $button_box_shadow_inset_color /* inner shadow */; + background-image: $button_ie9_gradient_hover; /* gradient fill */ + background-image: -moz-linear-gradient(90deg, $button_top_gradient_hover 0%, $button_bottom_gradient_hover 100%); /* gradient fill */ + background-image: -o-linear-gradient(90deg, $button_top_gradient_hover 0%, $button_bottom_gradient_hover 100%); /* gradient fill */ + background-image: -webkit-linear-gradient(90deg, $button_top_gradient_hover 0%, $button_bottom_gradient_hover 100%); /* gradient fill */ + background-image: linear-gradient(90deg, $button_top_gradient_hover 0%, $button_bottom_gradient_hover 100%); /* gradient fill */ + text-decoration: none; +} + +.blue_button:active { + -moz-box-shadow: + 0 1px 1px $button_box_shadow_color /* drop shadow */, + inset 0 3px 5px $button_box_shadow_inset_color /* inner shadow */; + -webkit-box-shadow: + 0 1px 1px $button_box_shadow_color /* drop shadow */, + inset 0 3px 5px $button_box_shadow_inset_color /* inner shadow */; + box-shadow: + 0 1px 1px $button_box_shadow_color /* drop shadow */, + inset 0 3px 5px $button_box_shadow_inset_color /* inner shadow */; + background-image: $button_ie9_gradient_active /* gradient fill */; + background-image: -moz-linear-gradient(90deg, $button_top_gradient_active 0%, $button_bottom_gradient_active 100%); /* gradient fill */ + background-image: -o-linear-gradient(90deg, $button_top_gradient_active 0%, $button_bottom_gradient_active 100%); /* gradient fill */ + background-image: -webkit-linear-gradient(90deg, $button_top_gradient_active 0%, $button_bottom_gradient_active 100%); /* gradient fill */ + background-image: linear-gradient(90deg, $button_top_gradient_active 0%, $button_bottom_gradient_active 100%); /* gradient fill */ +} \ No newline at end of file diff --git a/app/assets/stylesheets/reset.css b/app/assets/stylesheets/reset.css new file mode 100644 index 000000000..af944401f --- /dev/null +++ b/app/assets/stylesheets/reset.css @@ -0,0 +1,48 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +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, 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, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} \ No newline at end of file diff --git a/app/assets/stylesheets/share.css.scss b/app/assets/stylesheets/share.css.scss new file mode 100644 index 000000000..6d0221be4 --- /dev/null +++ b/app/assets/stylesheets/share.css.scss @@ -0,0 +1,50 @@ +#share_container +{ + #congrats + { + padding: 70px 0; + h2 + { + margin-bottom: 24px; + } + p + { + margin-bottom: 30px; + font-size: 24px; + } + } + #share + { + margin: 0 auto; + text-align: center; + margin: 0 auto; + #facebook_button_container + { + margin: 0 auto; + display: inline-block; + } + #pin_button_container + { + margin: 0 auto; + display: inline-block; + position: relative; + top: 1px; + .pin-it-button + { + } + } + #tweet_button_container + { + margin: 0 auto; + display: inline-block; + } + } + #order_id + { + margin: 0 auto; + margin-top: 15px; + padding: 0px; + opacity: 0.3; + z-index: 9999; + } +} diff --git a/app/assets/stylesheets/variables.css.scss b/app/assets/stylesheets/variables.css.scss new file mode 100644 index 000000000..b01cb55a0 --- /dev/null +++ b/app/assets/stylesheets/variables.css.scss @@ -0,0 +1,63 @@ +// Hi! +// Please change around the settings as you need. These are all the defaults +// These only affect the primitives -- inputs, divs, h1-h5, etc (not classes/IDs, with one exception) + +// If you have any questions, create a GitHub issue, or email me us -- hello@lockitron.com + +$body_background: #E6E6E6; + +// Right now, we don't really use h1 and h2's correctly. +// We'll fix it soon! + +$h1_color: #323232; +$h2_color: #4B4B4B; +$h4_color: #292929; +$h5_color: #4B4B4B; + +$text_color: #6B6B6B; +$link_color: #0008D6; +$text_shadow: 0 1px 0px #fff; +$font_size: 22px; + +// Lockitron uses ProximaNova Regular, but that costs money, so we're defaulting to Helveitca Neue instead. +$primary_font: "Helvetica Neue"; +$secondary_font: "Helvetica"; +$tertiary_font: "Arial"; + +// Gray background is a gradient -- top == 0%, middle == 50%, bottom == 100% +$gray_background_top_color: #F6F6F6; +$gray_background_middle_color: #FAFAFA; +$gray_background_bottom_color: #FAFAFA; + +// The bottom border on the gray backgrounds +$gray_background_border_color: #C4C4C4; + +// Button colors/background/border +$button_color: white; +$button_hovered_color: #0088d6; +$button_active_background: #FAFAFA; +$button_active_border: #C8C8C8; + +// This only affects .blue_button, which is the "Reserve Now" button you see on Lockitron's homepage +$button_text_shadow_color: rgba(0,0,0,.37); +$button_box_shadow_color: rgba(255,255,255,.92); +$button_box_shadow_inset_color: rgba(0,0,0,.22); +$button_border_radius: 10px; + +// Default State +$button_ie9_gradient: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGxpbmVhckdyYWRpZW50IGlkPSJoYXQwIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjEwMCUiIHgyPSI1MCUiIHkyPSIwJSI+CjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMwZTk2ZTQiIHN0b3Atb3BhY2l0eT0iMSIvPgo8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMmEwZmEiIHN0b3Atb3BhY2l0eT0iMSIvPgogICA8L2xpbmVhckdyYWRpZW50PgoKPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNoYXQwKSIgLz4KPC9zdmc+); +$button_top_gradient: #0E96E4; +$button_bottom_gradient: #02A0FA; + +// Hover State +$button_ie9_gradient_hover: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGxpbmVhckdyYWRpZW50IGlkPSJoYXQwIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjEwMCUiIHgyPSI1MCUiIHkyPSIwJSI+CjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMyZGE0ZTkiIHN0b3Atb3BhY2l0eT0iMSIvPgo8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMyMWFlZmYiIHN0b3Atb3BhY2l0eT0iMSIvPgogICA8L2xpbmVhckdyYWRpZW50PgoKPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNoYXQwKSIgLz4KPC9zdmc+); +$button_top_gradient_hover: #2DA4E9; +$button_bottom_gradient_hover: #21AEFF; + +// Active State +$button_ie9_gradient_active: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGxpbmVhckdyYWRpZW50IGlkPSJoYXQwIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjEwMCUiIHgyPSI1MCUiIHkyPSIwJSI+CjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMwMzlmZjciIHN0b3Atb3BhY2l0eT0iMSIvPgo8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMzlmZjciIHN0b3Atb3BhY2l0eT0iMSIvPgogICA8L2xpbmVhckdyYWRpZW50PgoKPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNoYXQwKSIgLz4KPC9zdmc+); +$button_top_gradient_active: #039FF7; +$button_bottom_gradient_active: #039ff7; + +// FAQ Entry +$summary_color: #0088D6; \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 000000000..e8065d950 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,3 @@ +class ApplicationController < ActionController::Base + protect_from_forgery +end diff --git a/app/controllers/preorder_controller.rb b/app/controllers/preorder_controller.rb new file mode 100644 index 000000000..2367fc084 --- /dev/null +++ b/app/controllers/preorder_controller.rb @@ -0,0 +1,42 @@ +class PreorderController < ApplicationController + skip_before_filter :verify_authenticity_token, :only => :ipn + + def index + + end + + def checkout + + end + + def prefill + @user = User.find_or_create_by_email!(params[:email]) + @order = Order.prefill!(:name => Settings.product_name, :price => Settings.price, :user_id => @user.id) + + # This is where all the magic happens. We create a multi-use token with Amazon, letting us charge the user's Amazon account + # Then, if they confirm the payment, Amazon POSTs us their shipping details and phone number + # From there, we save it, and voila, we got ourselves a preorder! + @pipeline = AmazonFlexPay.multi_use_pipeline(@order.uuid, :transaction_amount => Settings.price, :global_amount_limit => Settings.charge_limit, :collect_shipping_address => "True", :payment_reason => Settings.payment_description) + redirect_to @pipeline.url("#{request.scheme}://#{request.host}/preorder/postfill") + end + + def postfill + unless params[:callerReference].blank? + @order = Order.postfill!(params) + end + # "A" means the user cancelled the preorder before clicking "Confirm" on Amazon Payments. + if params['status'] != 'A' && @order.present? + redirect_to :action => :share, :uuid => @order.uuid + else + redirect_to root_url + end + end + + def share + @order = Order.find_by_uuid(params[:uuid]) + end + + def ipn + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 000000000..de6be7945 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/helpers/preorder_helper.rb b/app/helpers/preorder_helper.rb new file mode 100644 index 000000000..8372d05a8 --- /dev/null +++ b/app/helpers/preorder_helper.rb @@ -0,0 +1,17 @@ +module PreorderHelper + def like_button(width = 70, show_faces = false) + raw "
" + end + def pin_it_button + image_url = URI.encode("#{request.scheme}://#{request.host}#{image_path(Settings.product_image_url)}") + raw "" + end + def tweet_button + tweet_text = "I'm #{Settings.primary_stat_verb} number #{number_with_delimiter @order.number, :delimiter => ","} #{Settings.tweet_text}!" + raw "" + end + + def encoded_root_url + raw URI.encode "#{request.scheme}://#{request.host}/preorder" + end +end diff --git a/app/mailers/.gitkeep b/app/mailers/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/.gitkeep b/app/models/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 000000000..882142892 --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,68 @@ +class Order < ActiveRecord::Base + attr_accessible :address_one, :address_two, :city, :country, :number, :state, :status, :token, :transaction_id, :zip, :shipping, :tracking_number, :name, :price, :phone, :expiration + attr_readonly :uuid + before_validation :generate_uuid!, :on => :create + belongs_to :user + self.primary_key = 'uuid' + + + # This is where we create our Caller Reference for Amazon Payments, and prefill some other information. + def self.prefill!(options = {}) + @order = Order.new + @order.name = options[:name] + @order.user_id = options[:user_id] + @order.price = options[:price] + @order.number = Order.next_order_number || 1 + @order.save! + + return @order + end + + # After authenticating with Amazon, we get the rest of the details + def self.postfill!(options = {}) + @order = Order.find_by_uuid!(options[:callerReference]) + @order.token = options[:tokenID] + if !@order.token.blank? + @order.address_one = options[:addressLine1] + @order.address_two = options[:addressLine2] + @order.city = options[:city] + @order.state = options[:state] + @order.status = options[:status] + @order.zip = options[:zip] + @order.phone = options[:phoneNumber] + @order.country = options[:country] + @order.expiration = Date.parse(options[:expiry]) + @order.save! + + @order + end + end + + def self.next_order_number + Order.order("number DESC").limit(1).first.number.to_i + 1 if Order.count > 0 + end + + def generate_uuid! + self.uuid = SecureRandom.hex(16) + end + + # Implement these three methods to + def self.goal + Settings.project_goal + end + + def self.percent + (Order.current.to_f / Order.goal.to_f) * 100.to_f + end + + # See what it looks like when you have some backers! Drop in a number instead of Order.count + def self.current + Order.count + end + + def self.revenue + Order.current.to_f * Settings.price + end + + validates_presence_of :name, :price, :user_id +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 000000000..c388e7e38 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,4 @@ +class User < ActiveRecord::Base + attr_accessible :email + has_many :orders +end diff --git a/app/views/layouts/_footer.html.erb b/app/views/layouts/_footer.html.erb new file mode 100644 index 000000000..635aa49c9 --- /dev/null +++ b/app/views/layouts/_footer.html.erb @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 000000000..d2436b067 --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,14 @@ + + + + +<%= Settings.product_name %> + <%= stylesheet_link_tag "application" %> + <%= javascript_include_tag "application" %> + + + <%= render 'header' %> + <%= yield %> + <%= render 'footer' %> + + diff --git a/app/views/preorder/_copyright.html.erb b/app/views/preorder/_copyright.html.erb new file mode 100644 index 000000000..628810df4 --- /dev/null +++ b/app/views/preorder/_copyright.html.erb @@ -0,0 +1 @@ +

© You. Made by the guys at Lockitron. MIT License.

diff --git a/app/views/preorder/_footer.html.erb b/app/views/preorder/_footer.html.erb new file mode 100644 index 000000000..e62031a72 --- /dev/null +++ b/app/views/preorder/_footer.html.erb @@ -0,0 +1,6 @@ + +<%= render 'google_analytics' %> \ No newline at end of file diff --git a/app/views/preorder/_google_analytics.html.erb b/app/views/preorder/_google_analytics.html.erb new file mode 100644 index 000000000..740b4d045 --- /dev/null +++ b/app/views/preorder/_google_analytics.html.erb @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/app/views/preorder/_header.html.erb b/app/views/preorder/_header.html.erb new file mode 100644 index 000000000..d1ef3f05d --- /dev/null +++ b/app/views/preorder/_header.html.erb @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/app/views/preorder/checkout.html.erb b/app/views/preorder/checkout.html.erb new file mode 100644 index 000000000..b42d2aa18 --- /dev/null +++ b/app/views/preorder/checkout.html.erb @@ -0,0 +1,20 @@ +
+
+
+

Check out

+

+ Let your backers know how their payment information will be handled. +
+
+ Enter your email address below. +

+ <%= form_tag "/preorder/prefill", :id => "checkout" do %> + <%= email_field_tag "email", nil, :placeholder => "hello@lockitron.com", :required => "required", :id => "email" %> + <%= hidden_field_tag "preorder", true %> + <%= hidden_field_tag "quantity", params[:quantity] %> + <%= submit_tag "Checkout", :class => "blue_button disabled", :id => "amazon_button" %> + <% end %> +
+ <%= render 'preorder/checkout/sidebar' %> +
+
\ No newline at end of file diff --git a/app/views/preorder/checkout/_sidebar.html.erb b/app/views/preorder/checkout/_sidebar.html.erb new file mode 100644 index 000000000..8e2ad5a80 --- /dev/null +++ b/app/views/preorder/checkout/_sidebar.html.erb @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/app/views/preorder/homepage/_faqs.html.erb b/app/views/preorder/homepage/_faqs.html.erb new file mode 100644 index 000000000..25290c579 --- /dev/null +++ b/app/views/preorder/homepage/_faqs.html.erb @@ -0,0 +1,71 @@ +
+
+

Frequently Asked Questions

+
    +
  • +
    + How do I setup Amazon Payments? +

    You'll need to create an Amazon Seller Central account. Afterwards, get your access key and secret key from the "Integration" tab on your AWS account. Click here for more info. +
    +
    + Once you have your access key and secret key, head over to config/settings.yml. Change amazon_access_key and amazon_secret_key appropriately.

    +
    +
  • +
  • +
    + Can I use another payments provider? +

    Of course. We haven't built in support for other providers, but we recommend that you take a look at Stripe or WePay.

    +
    +
  • +
  • +
    + How do I edit the FAQ? +

    The faq is a partial located in app/views/preorder/homepage/_faq.html.erb The summary tag is the title, the p is the body. Make sure to add an li tag for each FAQ entry.

    +
    +
  • +
  • +
    + How do I change around the images, product name, etc? +

    The best way is in config/settings.yml. It has variables for several different parts, the YouTube video, the product name, the call to action button ("Fork Now"), and several more. +

    +
    +
  • +
+
    +
  • +
    + How do I change the CSS? +

    Head over to app/assets/stylesheets/variables.css.scss. It makes it easy to change around the elements used throughout the HTML. +
    +
    + Alternatively, you can dive right into the CSS, have a look at app/assets/stylesheets/main.css.scss.

    +
    +
  • +
  • +
    + Why did you release this? +

    Hardware startups are less welcome on Kickstarter than they were 6 months ago. We needed to roll our own kickstarter, so we did. Other hardware startups probably will too, so we made it easier for them by open sourcing our way of doing it.

    +
    +
  • +
  • +
    + What software stack does this use? +

    It's a Ruby on Rails app that makes heavy use of SCSS, Kickstarter's wonderful amazon_flex_pay gem, and a hint of CoffeeScript.

    +
    +
  • +
  • +
    + How do I deploy it? +

    We recommend using Heroku. We include a Procfile for you, so all you need to do is: +

    +

    Install the Heroku Toolbelt

    +

    Run heroku create in Selfstarter's folder

    +

    Run git push heroku master in Selfstarter's folder

    +

    +

    +
    +
  • +
+
+
+ \ No newline at end of file diff --git a/app/views/preorder/homepage/_key_points.html.erb b/app/views/preorder/homepage/_key_points.html.erb new file mode 100644 index 000000000..9f864233c --- /dev/null +++ b/app/views/preorder/homepage/_key_points.html.erb @@ -0,0 +1,51 @@ +
+
+
+

+ What is Selfstarter? +

+

+ Selfstarter is an open source starting point for building your own ad-hoc crowdfunding site. It was put together by Lockitron after they were turned down from Kickstarter. +

+

+
+
+ +
+
+
+

+ How do I use it? +

+

+ Selftstarter is a starting point for you to build your own solution. It is set up to collect reservations using Amazon Payments, but you can choose you own provider too. +

+

+
+
+ +
+
+
+

+ It's just a skeleton +

+

+ We've kept Selfstarter really simple, but that also means that you should beef it up with your own authentication, administration and product management code. +

+

+
+
+ +
+
+
+

+ Let's get started +

+

+ Most of what you need to get started is in the Readme. Selfstarter is based on Ruby on Rails, and we've tried to break up all of the different parts in a sensible fashion. +

+

+
+
\ No newline at end of file diff --git a/app/views/preorder/homepage/_middle_reserve.html.erb b/app/views/preorder/homepage/_middle_reserve.html.erb new file mode 100644 index 000000000..6cf1a3ca6 --- /dev/null +++ b/app/views/preorder/homepage/_middle_reserve.html.erb @@ -0,0 +1,6 @@ +
+
+

<%= Settings.ships %>

+ <%= Settings.middle_reserve_text %> +
+
\ No newline at end of file diff --git a/app/views/preorder/homepage/_other_points.html.erb b/app/views/preorder/homepage/_other_points.html.erb new file mode 100644 index 000000000..a54579c1e --- /dev/null +++ b/app/views/preorder/homepage/_other_points.html.erb @@ -0,0 +1,20 @@ +
+
    +
  • +

    Section 1

    +

    Morbi tempus dapibus egestas. Nullam accumsan dolor ut purus ornare congue. Phasellus ac commodo neque. Quisque non ligula lacus, id hendrerit eros.

    +
  • +
  • +

    Section 2

    +

    Vivamus nec posuere mauris. Suspendisse mi sem, egestas ac tristique ac, varius ac lectus. Sed porttitor dolor adipiscing mauris sagittis.

    +
  • +
  • +

    Section 3

    +

    Curabitur dolor elit, placerat et malesuada et, tristique vel nulla. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

    +
  • +
  • +

    Section 4

    +

    Curabitur ac mi elit, nec tempor odio. Nam sollicitudin, sapien sit amet elementum pretium, turpis mi fermentum nisl, ac vehicula purus lacus non velit.

    +
  • +
+
\ No newline at end of file diff --git a/app/views/preorder/homepage/_press.html.erb b/app/views/preorder/homepage/_press.html.erb new file mode 100644 index 000000000..f837db692 --- /dev/null +++ b/app/views/preorder/homepage/_press.html.erb @@ -0,0 +1,8 @@ +
+
    +
  • +
  • +
  • +
  • +
+
\ No newline at end of file diff --git a/app/views/preorder/homepage/_show_dont_tell.html.erb b/app/views/preorder/homepage/_show_dont_tell.html.erb new file mode 100644 index 000000000..008d90899 --- /dev/null +++ b/app/views/preorder/homepage/_show_dont_tell.html.erb @@ -0,0 +1,4 @@ +
+ <%= render 'preorder/homepage/value_proposition' %> + <%= render 'preorder/homepage/stats' %> +
\ No newline at end of file diff --git a/app/views/preorder/homepage/_stats.html.erb b/app/views/preorder/homepage/_stats.html.erb new file mode 100644 index 000000000..d04455d06 --- /dev/null +++ b/app/views/preorder/homepage/_stats.html.erb @@ -0,0 +1,53 @@ +
+
+ +
+ +
+
    +
  • + <%= number_with_delimiter Order.current, :delimiter => "," %> + <%= Settings.primary_stat %> +
  • +
  • + <%= number_to_currency Order.revenue, :precision => 0 %> + of <%= number_to_currency Settings.project_goal.to_f * Settings.price.to_f, :precision => 0 %> +
  • + + <% if Settings.expiration_date.present? %> +
  • + <%= distance_of_time_in_words_to_now(Settings.expiration_date).gsub(/\D/, "") %> + <%= distance_of_time_in_words_to_now(Settings.expiration_date).gsub(/\d/, "").gsub("about", "") %> left +
  • + <% else %> +
  • + ∞ + days left +
  • + <% end %> +
+ + <% if Order.current < Order.goal %> +
+
+
+
+ <% else %> +
+
+
+
<%= Order.percent %>% <%= Settings.progress_text %>
+
+ <% end %> + +
+

<%= Settings.ships %>

+ <%= Settings.call_to_action %> +

<%= Settings.price_human %>

+

<%= Settings.dont_give_them_a_reason_to_say_no %>

+ <%= like_button %> +
+ +
+ +
\ No newline at end of file diff --git a/app/views/preorder/homepage/_value_proposition.html.erb b/app/views/preorder/homepage/_value_proposition.html.erb new file mode 100644 index 000000000..af64913b0 --- /dev/null +++ b/app/views/preorder/homepage/_value_proposition.html.erb @@ -0,0 +1,3 @@ +
+

<%= Settings.value_proposition %>

+
\ No newline at end of file diff --git a/app/views/preorder/index.html.erb b/app/views/preorder/index.html.erb new file mode 100644 index 000000000..f255f52c1 --- /dev/null +++ b/app/views/preorder/index.html.erb @@ -0,0 +1,6 @@ +<%= render 'preorder/homepage/show_dont_tell' %> +<%= render 'preorder/homepage/key_points' %> +<%= render 'preorder/homepage/other_points' %> +<%= render 'preorder/homepage/middle_reserve' %> +<%= render 'preorder/homepage/faqs' %> +<%= render 'preorder/homepage/press' %> \ No newline at end of file diff --git a/app/views/preorder/share.html.erb b/app/views/preorder/share.html.erb new file mode 100644 index 000000000..a4449a49c --- /dev/null +++ b/app/views/preorder/share.html.erb @@ -0,0 +1,26 @@ +
+
+

+ Hooray! You've just reserved a <%= Settings.product_name %>! +

+

Congratulations, you're <%= Settings.primary_stat_verb %> number <%= number_with_delimiter @order.number, :delimiter => "," %>, in supporting <%= Settings.product_name %>. Share the great news!

+
+
+
+
+ <%= pin_it_button %> +
+
+ <%= tweet_button %> +
+
+ <%= like_button(450, true) %> +
+
+
Reservation ID: <%= @order.uuid %>. You can bookmark or print this page for your records.
+
+ +
+ +<%= render 'preorder/share/twitter_js' %> +<%= render 'preorder/share/facebook_js' %> \ No newline at end of file diff --git a/app/views/preorder/share/_facebook_js.html.erb b/app/views/preorder/share/_facebook_js.html.erb new file mode 100644 index 000000000..80c22a26f --- /dev/null +++ b/app/views/preorder/share/_facebook_js.html.erb @@ -0,0 +1,8 @@ +
+ \ No newline at end of file diff --git a/app/views/preorder/share/_twitter_js.html.erb b/app/views/preorder/share/_twitter_js.html.erb new file mode 100644 index 000000000..a915eb149 --- /dev/null +++ b/app/views/preorder/share/_twitter_js.html.erb @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/config.ru b/config.ru new file mode 100644 index 000000000..d04d29d04 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run Selfstarter::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 000000000..859633e32 --- /dev/null +++ b/config/application.rb @@ -0,0 +1,24 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +if defined?(Bundler) + Bundler.require(*Rails.groups(:assets => %w(development test))) +end + +module Selfstarter + + class Application < Rails::Application + + # --- Standard Rails Config --- + config.time_zone = 'Pacific Time (US & Canada)' + config.encoding = "utf-8" + config.filter_parameters += [:password] + config.active_record.whitelist_attributes = true + # Enable the asset pipeline + config.assets.enabled = true + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' + # --- Standard Rails Config --- + end +end \ No newline at end of file diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 000000000..4489e5868 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,6 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 000000000..51a4dd459 --- /dev/null +++ b/config/database.yml @@ -0,0 +1,25 @@ +# SQLite version 3.x +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem 'sqlite3' +development: + adapter: sqlite3 + database: db/development.sqlite3 + pool: 5 + timeout: 5000 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlite3 + database: db/test.sqlite3 + pool: 5 + timeout: 5000 + +production: + adapter: sqlite3 + database: db/production.sqlite3 + pool: 5 + timeout: 5000 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 000000000..6ea462bfb --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +Selfstarter::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 000000000..d36d45a39 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,37 @@ +Selfstarter::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL) + config.active_record.auto_explain_threshold_in_seconds = 0.5 + + # Do not compress assets + config.assets.compress = false + + # Expands the lines which load the assets + config.assets.debug = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 000000000..9d5fdbc47 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,67 @@ +Selfstarter::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # Code is not reloaded between requests + config.cache_classes = true + + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Disable Rails's static asset server (Apache or nginx will already do this) + config.serve_static_assets = false + + # Compress JavaScripts and CSS + config.assets.compress = true + + # Don't fallback to assets pipeline if a precompiled asset is missed + config.assets.compile = false + + # Generate digests for assets URLs + config.assets.digest = true + + # Defaults to nil and saved in location specified by config.assets.prefix + # config.assets.manifest = YOUR_PATH + + # Specifies the header that your server uses for sending files + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Prepend all log lines with the following tags + # config.log_tags = [ :subdomain, :uuid ] + + # Use a different logger for distributed setups + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) + config.assets.precompile += %w( application.js application.css ) + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify + + # Log the query plan for queries taking more than this (works + # with SQLite, MySQL, and PostgreSQL) + # config.active_record.auto_explain_threshold_in_seconds = 0.5 +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 000000000..68f355224 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,37 @@ +Selfstarter::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Configure static asset server for tests with Cache-Control for performance + config.serve_static_assets = true + config.static_cache_control = "public, max-age=3600" + + # Log error messages when you accidentally call methods on nil + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Raise exception on mass assignment protection for Active Record models + config.active_record.mass_assignment_sanitizer = :strict + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr +end diff --git a/config/initializers/amazon_flexible_payments.rb b/config/initializers/amazon_flexible_payments.rb new file mode 100644 index 000000000..62a31e947 --- /dev/null +++ b/config/initializers/amazon_flexible_payments.rb @@ -0,0 +1,3 @@ +AmazonFlexPay.access_key = Settings.amazon_access_key +AmazonFlexPay.secret_key = Settings.amazon_secret_key +AmazonFlexPay.go_live! if Rails.env.production? \ No newline at end of file diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 000000000..59385cdf3 --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 000000000..5d8d9be23 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,15 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end +# +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.acronym 'RESTful' +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 000000000..72aca7e44 --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone diff --git a/config/initializers/rails_config.rb b/config/initializers/rails_config.rb new file mode 100644 index 000000000..5378de942 --- /dev/null +++ b/config/initializers/rails_config.rb @@ -0,0 +1,3 @@ +RailsConfig.setup do |config| + config.const_name = "Settings" +end \ No newline at end of file diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 000000000..99cfc7b44 --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +Selfstarter::Application.config.secret_token = '686a073cf783e29dee02cb7544762d17a7c769acf7baa148a0d9726a39e45123532418f9ce7cd3def2ca0e3d5bff9d0b9ffd41f19b0c6b6dd9d0cc10b77fc5ae' diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 000000000..22bb7161b --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +Selfstarter::Application.config.session_store :cookie_store, key: '_Selfstarter_session' + +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rails generate session_migration") +# Selfstarter::Application.config.session_store :active_record_store diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 000000000..999df2018 --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# Disable root element in JSON by default. +ActiveSupport.on_load(:active_record) do + self.include_root_in_json = false +end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 000000000..179c14ca5 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,5 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + hello: "Hello world" diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 000000000..d1fe958c6 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,11 @@ +Selfstarter::Application.routes.draw do + root :to => "preorder#index" + + match '/preorder' => 'preorder#index' + get "preorder/checkout" + match '/preorder/share/:uuid' => 'preorder#share', :via => :get + match '/preorder/ipn' => 'preorder#ipn', :via => :post + match '/preorder/prefill' => 'preorder#prefill' + match '/preorder/postfill' => 'preorder#postfill' + +end diff --git a/config/settings.yml b/config/settings.yml new file mode 100644 index 000000000..0a28c0b3f --- /dev/null +++ b/config/settings.yml @@ -0,0 +1,80 @@ +# Hi there! +# These are the settings for Selfstarter. +# This is more tidy than changing the HTML if all you want to do is rename things and swap out images + +# You should totally change the HTML and CSS though +# Checkout app/assets/stylesheets/variables.css.scss to change around the CSS quickly + +# Set your project goal here - if you manually want to adjust your progress to test the site, head over to the Order model (app/models/order.rb) +project_goal: 100 +# If you want to edit the FAQ, head over to app/views/preorder/homepage/_faqs.html.erb + +# This'll be both the page title () and the name in the header +product_name: "Selfstarter" + +# An image showcasing your product -- it'll show up when you pin your product +# It should be in app/assets/images +product_image_path: "my-product-image.png" + +# The message on the preorder page, Lockitron's +value_proposition: "Roll your own crowdfunding" + +# YouTube Video URL (The embed URL, without the query string options) +# There's no Vimeo support at the moment, but feel free to implement it and send a pull request! +youtube_embed_url: "https://www.youtube.com/v/D1L3o88GKew" + +# Amazon settings -- you'll need an Amazon Payments account, sign up here --> http://bit.ly/SGksTv + +# To find your access key and secret key, head over to here --> http://bit.ly/R4I4ky (Follow that guide in the Seller Central page) +amazon_access_key: "YOUR_AMAZON_ACCESS_KEY" +amazon_secret_key: "YOUR_AMAZON_SECRET_KEY" +price: 19.95 + +payment_description: "You really should change this text because people will see it on Amazon's order page!!!!!" + +# Amazon limits how much we can charge people with their Multi-Use tokens. +# You probably should add some leeway to account for international shipping +charge_limit: 25.00 + +# Stats settings + +# On Lockitron, it's "backers" +primary_stat: "backers" +# This'll show up in the tweet as, "I'm forker number ..." +primary_stat_verb: 'backer' + +# The 2nd call to action button, towards the middle-ish of the page +middle_reserve_text: "Reserve Now" + +# When the project should end +expiration_date: <%= DateTime.now + 29 %> + +# Text to show inside the progress bar, when the goal reaches/exceeds 100% +progress_text: "Implemented" + +# Call to action section + +# On Lockitron, it's "First Batch Ships in March 2013" +ships: "Ships...sometime" + +# On Lockitron, it's "Reserve Now" +call_to_action: "Reserve Now" +# On Lockitron, this is "Only $149 for a limited time" +price_human: "It costs money!" + +# The paragraph below the price. You'd probably say something about how you're not going to charge them before it ships (so it's less risky). +dont_give_them_a_reason_to_say_no: "You'll get this exact site. All you'll need to get started is a great product." + +# Social Stuff +facebook_app_id: "1234567890" +# Tweets are prefixed with "I'm #{Settings.primary_stat} number X for #{Settings.product_name}" +# Maybe mention something about your product vision -- e.g. "to replace keys with my phone" +tweet_text: "to crowdfund" + +# Google Analytics +google_id: "1234567890" + +# If you want to change the images for the key points (e.g. "Kickstarter is not a store") +# They're in app/assets/images/#{pointer_number}-background.png +# So, the first key point, it's at app/assets/images/1-background.png +# Alternatively, change it up in app/assets/stylesheets/homepage/key_points.css.scss \ No newline at end of file diff --git a/config/settings/development.yml b/config/settings/development.yml new file mode 100644 index 000000000..e69de29bb diff --git a/config/settings/production.yml b/config/settings/production.yml new file mode 100644 index 000000000..e69de29bb diff --git a/config/settings/test.yml b/config/settings/test.yml new file mode 100644 index 000000000..e69de29bb diff --git a/db/migrate/20121004072615_create_users.rb b/db/migrate/20121004072615_create_users.rb new file mode 100644 index 000000000..b5dc108bb --- /dev/null +++ b/db/migrate/20121004072615_create_users.rb @@ -0,0 +1,9 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :email + + t.timestamps + end + end +end diff --git a/db/migrate/20121004072706_create_orders.rb b/db/migrate/20121004072706_create_orders.rb new file mode 100644 index 000000000..5e46c60a6 --- /dev/null +++ b/db/migrate/20121004072706_create_orders.rb @@ -0,0 +1,26 @@ +class CreateOrders < ActiveRecord::Migration + def change + create_table :orders, :id => false do |t| + t.string :token + t.string :transaction_id + t.string :address_one + t.string :address_two + t.string :city + t.string :state + t.string :zip + t.string :country + t.string :status + t.string :number + t.string :uuid + t.string :user_id + t.decimal :price + t.decimal :shipping + t.string :tracking_number + t.string :phone + t.string :name + t.date :expiration + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 000000000..5feda63d7 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,45 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20121004072706) do + + create_table "orders", :id => false, :force => true do |t| + t.string "token" + t.string "transaction_id" + t.string "address_one" + t.string "address_two" + t.string "city" + t.string "state" + t.string "zip" + t.string "country" + t.string "status" + t.string "number" + t.string "uuid" + t.string "user_id" + t.decimal "price" + t.decimal "shipping" + t.string "tracking_number" + t.string "phone" + t.string "name" + t.date "expiration" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "users", :force => true do |t| + t.string "email" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 000000000..4edb1e857 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) +# Mayor.create(name: 'Emanuel', city: cities.first) diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP new file mode 100644 index 000000000..fe41f5cc2 --- /dev/null +++ b/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/lib/assets/.gitkeep b/lib/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/log/.gitkeep b/log/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/public/404.html b/public/404.html new file mode 100644 index 000000000..9a48320a5 --- /dev/null +++ b/public/404.html @@ -0,0 +1,26 @@ + + + + The page you were looking for doesn't exist (404) + + + + + +
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+ + diff --git a/public/422.html b/public/422.html new file mode 100644 index 000000000..83660ab18 --- /dev/null +++ b/public/422.html @@ -0,0 +1,26 @@ + + + + The change you wanted was rejected (422) + + + + + +
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+ + diff --git a/public/500.html b/public/500.html new file mode 100644 index 000000000..f3648a0db --- /dev/null +++ b/public/500.html @@ -0,0 +1,25 @@ + + + + We're sorry, but something went wrong (500) + + + + + +
+

We're sorry, but something went wrong.

+
+ + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 000000000..e69de29bb diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 000000000..085187fa5 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,5 @@ +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-Agent: * +# Disallow: / diff --git a/script/rails b/script/rails new file mode 100755 index 000000000..f8da2cffd --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands' diff --git a/test/fixtures/.gitkeep b/test/fixtures/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/orders.yml b/test/fixtures/orders.yml new file mode 100644 index 000000000..69c1c332e --- /dev/null +++ b/test/fixtures/orders.yml @@ -0,0 +1,27 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + token: MyString + transaction_id: MyString + address_one: MyString + address_two: MyString + city: MyString + state: MyString + zip: MyString + country: MyString + status: MyString + number: MyString + uuid: MyString + +two: + token: MyString + transaction_id: MyString + address_one: MyString + address_two: MyString + city: MyString + state: MyString + zip: MyString + country: MyString + status: MyString + number: MyString + uuid: MyString diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 000000000..abc883d94 --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + email: MyString + +two: + email: MyString diff --git a/test/functional/.gitkeep b/test/functional/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/functional/preorder_controller_test.rb b/test/functional/preorder_controller_test.rb new file mode 100644 index 000000000..34c1aecf0 --- /dev/null +++ b/test/functional/preorder_controller_test.rb @@ -0,0 +1,19 @@ +require 'test_helper' + +class PreorderControllerTest < ActionController::TestCase + test "should get index" do + get :index + assert_response :success + end + + test "should get checkout" do + get :checkout + assert_response :success + end + + test "should get get_excited" do + get :get_excited + assert_response :success + end + +end diff --git a/test/integration/.gitkeep b/test/integration/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb new file mode 100644 index 000000000..3fea27b91 --- /dev/null +++ b/test/performance/browsing_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' +require 'rails/performance_test_help' + +class BrowsingTest < ActionDispatch::PerformanceTest + # Refer to the documentation for all available options + # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] + # :output => 'tmp/performance', :formats => [:flat] } + + def test_homepage + get '/' + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 000000000..8bf1192ff --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,13 @@ +ENV["RAILS_ENV"] = "test" +require File.expand_path('../../config/environment', __FILE__) +require 'rails/test_help' + +class ActiveSupport::TestCase + # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. + # + # Note: You'll currently still have to declare fixtures explicitly in integration tests + # -- they do not yet inherit this setting + fixtures :all + + # Add more helper methods to be used by all tests here... +end diff --git a/test/unit/.gitkeep b/test/unit/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/unit/helpers/preorder_helper_test.rb b/test/unit/helpers/preorder_helper_test.rb new file mode 100644 index 000000000..54f9269d2 --- /dev/null +++ b/test/unit/helpers/preorder_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class PreorderHelperTest < ActionView::TestCase +end diff --git a/test/unit/order_test.rb b/test/unit/order_test.rb new file mode 100644 index 000000000..15b8ed134 --- /dev/null +++ b/test/unit/order_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class OrderTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb new file mode 100644 index 000000000..82f61e010 --- /dev/null +++ b/test/unit/user_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/vendor/assets/javascripts/.gitkeep b/vendor/assets/javascripts/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/assets/stylesheets/.gitkeep b/vendor/assets/stylesheets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep new file mode 100644 index 000000000..e69de29bb