From a36c272e2844fd1c7b521c26f898527ce0c4b43a Mon Sep 17 00:00:00 2001 From: yafeilee Date: Wed, 20 Apr 2016 16:03:27 +0800 Subject: [PATCH 01/14] Upgrade rails4 -> rails5.beta3 --- Gemfile | 23 ++--- Gemfile.lock | 231 ++++++++++++++++++++++++++------------------------- 2 files changed, 132 insertions(+), 122 deletions(-) diff --git a/Gemfile b/Gemfile index f7f2e1a..6be0ef0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,19 +1,20 @@ source 'https://rubygems.org' -gem 'rails', '4.2.5.2' -gem 'sass-rails' +ruby '2.2.3' + +gem 'rails', '>= 5.0.0.beta3', '< 5.1' +gem 'sass-rails', '~> 5.0' gem 'coffee-rails', '~> 4.1.0' gem 'uglifier', '>= 2.7.2' + gem 'jquery-rails' -gem 'foundation-rails', '~> 5.5.1' +gem 'foundation-rails', '~> 6.2.1' gem 'foundation-icons-sass-rails' gem 'font-awesome-sass' +gem 'angularjs-rails' gem 'jbuilder' -gem 'mongoid' -gem 'mongoid-tree' -gem 'mongoid-pagination' gem 'redcarpet' gem 'rouge' gem 'slim-rails' @@ -22,34 +23,36 @@ gem 'mini_magick' gem 'carrierwave-mongoid' gem 'html_truncator' gem 'nokogiri' -gem 'angularjs-rails' gem 'figaro' gem 'rqrcode-with-patches', require: 'rqrcode' gem 'chunky_png' gem 'sidekiq' gem 'redis-namespace' gem 'rest-client' -gem 'unicorn' gem 'newrelic_rpm' +gem 'unicorn' + gem 'mina', require: false gem 'mina-multistage', require: false gem 'mina-sidekiq', require: false gem 'mina-unicorn', require: false group :development do - gem 'spring' gem 'quiet_assets' gem 'guard' gem 'guard-rails' gem 'guard-rspec', require: false gem 'guard-bundler', require: false + gem 'listen', '~> 3.0.5' + gem 'spring' + gem 'spring-watcher-listen', '~> 2.0.0' + gem 'rack-cors', :require => 'rack/cors' end group :test do gem 'capybara' - gem 'mongoid-rspec', :require => false gem 'database_cleaner' gem 'rspec-sidekiq' gem "codeclimate-test-reporter", group: :test, require: nil diff --git a/Gemfile.lock b/Gemfile.lock index affa7d2..352f743 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,62 +1,67 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.5.2) - actionpack (= 4.2.5.2) - actionview (= 4.2.5.2) - activejob (= 4.2.5.2) + actioncable (5.0.0.beta3) + actionpack (= 5.0.0.beta3) + nio4r (~> 1.2) + websocket-driver (~> 0.6.1) + actionmailer (5.0.0.beta3) + actionpack (= 5.0.0.beta3) + actionview (= 5.0.0.beta3) + activejob (= 5.0.0.beta3) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.5.2) - actionview (= 4.2.5.2) - activesupport (= 4.2.5.2) - rack (~> 1.6) - rack-test (~> 0.6.2) + actionpack (5.0.0.beta3) + actionview (= 5.0.0.beta3) + activesupport (= 5.0.0.beta3) + rack (~> 2.x) + rack-test (~> 0.6.3) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.5.2) - activesupport (= 4.2.5.2) + actionview (5.0.0.beta3) + activesupport (= 5.0.0.beta3) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.5.2) - activesupport (= 4.2.5.2) - globalid (>= 0.3.0) - activemodel (4.2.5.2) - activesupport (= 4.2.5.2) - builder (~> 3.1) - activerecord (4.2.5.2) - activemodel (= 4.2.5.2) - activesupport (= 4.2.5.2) - arel (~> 6.0) - activesupport (4.2.5.2) + activejob (5.0.0.beta3) + activesupport (= 5.0.0.beta3) + globalid (>= 0.3.6) + activemodel (5.0.0.beta3) + activesupport (= 5.0.0.beta3) + activerecord (5.0.0.beta3) + activemodel (= 5.0.0.beta3) + activesupport (= 5.0.0.beta3) + arel (~> 7.0) + activesupport (5.0.0.beta3) + concurrent-ruby (~> 1.0) i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) addressable (2.4.0) angularjs-rails (1.5.0) - arel (6.0.3) - bson (4.0.4) + arel (7.0.0) + babel-source (5.8.35) + babel-transpiler (0.7.0) + babel-source (>= 4.0, < 6) + execjs (~> 2.0) + bson (4.1.0) builder (3.2.2) - capybara (2.6.2) + capybara (2.7.0) addressable mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) - carrierwave (0.10.0) + carrierwave (0.11.0) activemodel (>= 3.2.0) activesupport (>= 3.2.0) json (>= 1.7) mime-types (>= 1.16) - carrierwave-mongoid (0.8.1) - carrierwave (>= 0.8.0, < 0.11.0) - mongoid (>= 3.0, < 6.0) - mongoid-grid_fs (>= 1.3, < 3.0) + carrierwave-mongoid (0.1.0) + carrierwave + mongoid chunky_png (1.3.5) codeclimate-test-reporter (0.5.0) simplecov (>= 0.7.1, < 1.0.0) @@ -70,17 +75,18 @@ GEM coffee-script-source (1.10.0) concurrent-ruby (1.0.1) connection_pool (2.2.0) - database_cleaner (1.5.1) + database_cleaner (1.5.2) diff-lcs (1.2.5) docile (1.1.5) - domain_name (0.5.20160309) + domain_name (0.5.20160310) unf (>= 0.0.5, < 1.0.0) + durran-validatable (2.0.1) erubis (2.7.0) execjs (2.6.0) - factory_girl (4.5.0) + factory_girl (4.7.0) activesupport (>= 3.0.0) - factory_girl_rails (4.6.0) - factory_girl (~> 4.5.0) + factory_girl_rails (4.7.0) + factory_girl (~> 4.7.0) railties (>= 3.0.0) ffi (1.9.10) figaro (1.1.1) @@ -91,9 +97,10 @@ GEM foundation-icons-sass-rails (3.0.0) railties (>= 3.1.1) sass-rails (>= 3.1.1) - foundation-rails (5.5.3.2) + foundation-rails (6.2.1.0) railties (>= 3.1.0) sass (>= 3.3.0, < 3.5) + sprockets-es6 (>= 0.9.0) globalid (0.3.6) activesupport (>= 4.1.0) guard (2.13.0) @@ -113,7 +120,7 @@ GEM guard-rails (0.7.2) guard (~> 2.11) guard-compat (~> 1.0) - guard-rspec (4.6.4) + guard-rspec (4.6.5) guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) @@ -131,14 +138,15 @@ GEM thor (>= 0.14, < 2.0) json (1.8.3) kgio (2.10.0) + leshill-will_paginate (2.3.11) listen (3.0.6) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9.7) loofah (2.0.3) nokogiri (>= 1.5.9) lumberjack (1.0.10) - mail (2.6.3) - mime-types (>= 1.16, < 3) + mail (2.6.4) + mime-types (>= 1.16, < 4) method_source (0.8.2) mime-types (2.99.1) mina (0.3.8) @@ -149,39 +157,27 @@ GEM mina-sidekiq (0.3.1) mina mina-unicorn (0.4.0) - mini_magick (4.4.0) + mini_magick (4.5.1) mini_portile2 (2.0.0) minitest (5.8.4) mongo (2.2.4) bson (~> 4.0) - mongoid (5.1.1) - activemodel (~> 4.0) - mongo (~> 2.1) - origin (~> 2.2) - tzinfo (>= 0.3.37) - mongoid-grid_fs (2.2.1) - mime-types (>= 1.0, < 3.0) - mongoid (>= 3.0, < 6.0) - mongoid-pagination (0.2.0) - activesupport - mongoid - mongoid-rspec (3.0.0) - mongoid (~> 5.0) - rake - rspec (~> 3.3) - mongoid-tree (2.0.1) - mongoid (>= 4.0, < 6.0) + mongoid (1.0.6) + activesupport (>= 2.2.2) + durran-validatable (>= 2.0.1) + leshill-will_paginate (>= 2.3.11) + mongo (>= 0.18.2) multi_json (1.11.2) nenv (0.3.0) netrc (0.11.0) - newrelic_rpm (3.15.0.314) + newrelic_rpm (3.15.1.316) + nio4r (1.2.1) nokogiri (1.6.7.2) mini_portile2 (~> 2.0.0.rc2) notiffany (0.0.8) nenv (~> 0.1) shellany (~> 0.0) open4 (1.3.4) - origin (2.2.0) pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -192,21 +188,23 @@ GEM pry (>= 0.9.10) quiet_assets (1.1.0) railties (>= 3.1, < 5.0) - rack (1.6.4) + rack (2.0.0.alpha) + json rack-cors (0.4.0) rack-test (0.6.3) rack (>= 1.0) - rails (4.2.5.2) - actionmailer (= 4.2.5.2) - actionpack (= 4.2.5.2) - actionview (= 4.2.5.2) - activejob (= 4.2.5.2) - activemodel (= 4.2.5.2) - activerecord (= 4.2.5.2) - activesupport (= 4.2.5.2) + rails (5.0.0.beta3) + actioncable (= 5.0.0.beta3) + actionmailer (= 5.0.0.beta3) + actionpack (= 5.0.0.beta3) + actionview (= 5.0.0.beta3) + activejob (= 5.0.0.beta3) + activemodel (= 5.0.0.beta3) + activerecord (= 5.0.0.beta3) + activesupport (= 5.0.0.beta3) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.5.2) - sprockets-rails + railties (= 5.0.0.beta3) + sprockets-rails (>= 2.0.0) rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) rails-dom-testing (1.0.7) @@ -215,18 +213,19 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (4.2.5.2) - actionpack (= 4.2.5.2) - activesupport (= 4.2.5.2) + railties (5.0.0.beta3) + actionpack (= 5.0.0.beta3) + activesupport (= 5.0.0.beta3) + method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) raindrops (0.16.0) - rake (11.1.1) + rake (11.1.2) rb-fsevent (0.9.7) rb-inotify (0.9.7) ffi (>= 0.5.0) redcarpet (3.3.4) - redis (3.2.2) + redis (3.3.0) redis-namespace (1.5.2) redis (~> 3.0, >= 3.0.4) rest-client (1.8.0) @@ -236,31 +235,30 @@ GEM rouge (1.10.1) rqrcode-with-patches (0.6.0) chunky_png - rspec (3.4.0) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-core (3.4.4) - rspec-support (~> 3.4.0) - rspec-expectations (3.4.0) + rspec (3.1.0) + rspec-core (~> 3.1.0) + rspec-expectations (~> 3.1.0) + rspec-mocks (~> 3.1.0) + rspec-core (3.1.7) + rspec-support (~> 3.1.0) + rspec-expectations (3.1.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-mocks (3.4.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-rails (3.4.2) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-support (~> 3.4.0) + rspec-support (~> 3.1.0) + rspec-mocks (3.1.3) + rspec-support (~> 3.1.0) + rspec-rails (3.1.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.1.0) + rspec-expectations (~> 3.1.0) + rspec-mocks (~> 3.1.0) + rspec-support (~> 3.1.0) rspec-sidekiq (2.2.0) rspec (~> 3.0, >= 3.0.0) sidekiq (>= 2.4.0) - rspec-support (3.4.1) - sass (3.4.21) + rspec-support (3.1.2) + sass (3.4.22) sass-rails (5.0.4) railties (>= 4.0.0, < 5.0) sass (~> 3.1) @@ -290,10 +288,17 @@ GEM railties (>= 3.1, < 5.0) slim (~> 3.0) slop (3.6.0) - spring (1.6.4) - sprockets (3.5.2) + spring (1.7.1) + spring-watcher-listen (2.0.0) + listen (>= 2.7, < 4.0) + spring (~> 1.2) + sprockets (3.6.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) + sprockets-es6 (0.9.0) + babel-source (>= 5.8.11) + babel-transpiler + sprockets (>= 3.0.0) sprockets-rails (3.0.4) actionpack (>= 4.0) activesupport (>= 4.0) @@ -304,16 +309,17 @@ GEM tilt (2.0.2) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.7.2) - execjs (>= 0.3.0) - json (>= 1.8.0) + uglifier (3.0.0) + execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext unf_ext (0.0.7.2) - unicorn (5.0.1) + unicorn (5.1.0) kgio (~> 2.6) - rack raindrops (~> 0.7) + websocket-driver (0.6.3) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.2) xpath (2.0.0) nokogiri (~> 1.3) @@ -332,7 +338,7 @@ DEPENDENCIES figaro font-awesome-sass foundation-icons-sass-rails - foundation-rails (~> 5.5.1) + foundation-rails (~> 6.2.1) guard guard-bundler guard-rails @@ -340,22 +346,19 @@ DEPENDENCIES html_truncator jbuilder jquery-rails + listen (~> 3.0.5) mina mina-multistage mina-sidekiq mina-unicorn mini_magick - mongoid - mongoid-pagination - mongoid-rspec - mongoid-tree newrelic_rpm nokogiri pry-nav pry-rails quiet_assets rack-cors - rails (= 4.2.5.2) + rails (>= 5.0.0.beta3, < 5.1) redcarpet redis-namespace rest-client @@ -363,10 +366,14 @@ DEPENDENCIES rqrcode-with-patches rspec-rails (>= 2.8.1) rspec-sidekiq - sass-rails + sass-rails (~> 5.0) sidekiq simple_form slim-rails spring + spring-watcher-listen (~> 2.0.0) uglifier (>= 2.7.2) unicorn + +BUNDLED WITH + 1.11.2 From 859d6bbf221a21b3205a625f36650f13122d8536 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Wed, 20 Apr 2016 22:29:29 +0800 Subject: [PATCH 02/14] Refactor database with pg and foudation6( stage 1 ) --- .gitignore | 1 + Gemfile | 4 +- Gemfile.lock | 27 +- app/assets/javascripts/application.js | 6 +- app/assets/stylesheets/_settings.scss | 567 ++++++++ app/assets/stylesheets/application.scss | 16 +- .../stylesheets/foundation_and_overrides.scss | 1242 +---------------- app/assets/stylesheets/head.scss | 34 +- app/controllers/blogs_controller.rb | 6 +- app/models/application_record.rb | 3 + app/models/comment.rb | 11 +- app/models/label.rb | 7 +- app/models/like.rb | 4 +- app/models/photo.rb | 6 +- app/models/post.rb | 36 +- app/models/subscribe.rb | 6 +- app/views/layouts/application.html.slim | 48 +- config/application.rb | 10 +- config/database.yml | 20 + db/migrate/20160420082319_create_posts.rb | 11 + db/migrate/20160420082536_create_comments.rb | 12 + db/migrate/20160420082629_create_labels.rb | 9 + db/migrate/20160420082734_create_likes.rb | 9 + db/migrate/20160420082811_create_photos.rb | 9 + .../20160420082909_create_subscribes.rb | 10 + db/schema.rb | 61 + spec/models/comment_spec.rb | 5 + spec/models/label_spec.rb | 5 + spec/models/photo_spec.rb | 5 + 29 files changed, 858 insertions(+), 1332 deletions(-) create mode 100644 app/assets/stylesheets/_settings.scss create mode 100644 app/models/application_record.rb create mode 100644 config/database.yml create mode 100644 db/migrate/20160420082319_create_posts.rb create mode 100644 db/migrate/20160420082536_create_comments.rb create mode 100644 db/migrate/20160420082629_create_labels.rb create mode 100644 db/migrate/20160420082734_create_likes.rb create mode 100644 db/migrate/20160420082811_create_photos.rb create mode 100644 db/migrate/20160420082909_create_subscribes.rb create mode 100644 db/schema.rb create mode 100644 spec/models/comment_spec.rb create mode 100644 spec/models/label_spec.rb create mode 100644 spec/models/photo_spec.rb diff --git a/.gitignore b/.gitignore index cc8ff91..f256735 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ /config/mongoid.yml /public/assets/* *.old +*.bak diff --git a/Gemfile b/Gemfile index 6be0ef0..75aae8c 100644 --- a/Gemfile +++ b/Gemfile @@ -14,13 +14,13 @@ gem 'font-awesome-sass' gem 'angularjs-rails' gem 'jbuilder' +gem 'pg' gem 'redcarpet' gem 'rouge' gem 'slim-rails' gem 'simple_form' gem 'mini_magick' -gem 'carrierwave-mongoid' gem 'html_truncator' gem 'nokogiri' gem 'figaro' @@ -62,5 +62,5 @@ group :test, :development do gem "rspec-rails", ">= 2.8.1" gem 'pry-rails' gem 'pry-nav' - gem 'factory_girl_rails' + #gem 'factory_girl_rails' end diff --git a/Gemfile.lock b/Gemfile.lock index 352f743..602cdae 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -45,7 +45,6 @@ GEM babel-transpiler (0.7.0) babel-source (>= 4.0, < 6) execjs (~> 2.0) - bson (4.1.0) builder (3.2.2) capybara (2.7.0) addressable @@ -54,14 +53,6 @@ GEM rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) - carrierwave (0.11.0) - activemodel (>= 3.2.0) - activesupport (>= 3.2.0) - json (>= 1.7) - mime-types (>= 1.16) - carrierwave-mongoid (0.1.0) - carrierwave - mongoid chunky_png (1.3.5) codeclimate-test-reporter (0.5.0) simplecov (>= 0.7.1, < 1.0.0) @@ -80,14 +71,8 @@ GEM docile (1.1.5) domain_name (0.5.20160310) unf (>= 0.0.5, < 1.0.0) - durran-validatable (2.0.1) erubis (2.7.0) execjs (2.6.0) - factory_girl (4.7.0) - activesupport (>= 3.0.0) - factory_girl_rails (4.7.0) - factory_girl (~> 4.7.0) - railties (>= 3.0.0) ffi (1.9.10) figaro (1.1.1) thor (~> 0.14) @@ -138,7 +123,6 @@ GEM thor (>= 0.14, < 2.0) json (1.8.3) kgio (2.10.0) - leshill-will_paginate (2.3.11) listen (3.0.6) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9.7) @@ -160,13 +144,6 @@ GEM mini_magick (4.5.1) mini_portile2 (2.0.0) minitest (5.8.4) - mongo (2.2.4) - bson (~> 4.0) - mongoid (1.0.6) - activesupport (>= 2.2.2) - durran-validatable (>= 2.0.1) - leshill-will_paginate (>= 2.3.11) - mongo (>= 0.18.2) multi_json (1.11.2) nenv (0.3.0) netrc (0.11.0) @@ -178,6 +155,7 @@ GEM nenv (~> 0.1) shellany (~> 0.0) open4 (1.3.4) + pg (0.18.4) pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -329,12 +307,10 @@ PLATFORMS DEPENDENCIES angularjs-rails capybara - carrierwave-mongoid chunky_png codeclimate-test-reporter coffee-rails (~> 4.1.0) database_cleaner - factory_girl_rails figaro font-awesome-sass foundation-icons-sass-rails @@ -354,6 +330,7 @@ DEPENDENCIES mini_magick newrelic_rpm nokogiri + pg pry-nav pry-rails quiet_assets diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 5f08bb3..e2bb1c0 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,10 +1,6 @@ //= require jquery //= require jquery_ujs -//= require foundation/foundation -//= require foundation/foundation.alert -//= require foundation/foundation.topbar -//= require foundation/foundation.offcanvas -//= require foundation/foundation.magellan +//= require foundation //= require angularjs //= require 'jquery.html5-fileupload' //= require_tree . diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss new file mode 100644 index 0000000..bb9e883 --- /dev/null +++ b/app/assets/stylesheets/_settings.scss @@ -0,0 +1,567 @@ +// Foundation for Sites Settings +// ----------------------------- +// +// Table of Contents: +// +// 1. Global +// 2. Breakpoints +// 3. The Grid +// 4. Base Typography +// 5. Typography Helpers +// 6. Abide +// 7. Accordion +// 8. Accordion Menu +// 9. Badge +// 10. Breadcrumbs +// 11. Button +// 12. Button Group +// 13. Callout +// 14. Close Button +// 15. Drilldown +// 16. Dropdown +// 17. Dropdown Menu +// 18. Flex Video +// 19. Forms +// 20. Label +// 21. Media Object +// 22. Menu +// 23. Meter +// 24. Off-canvas +// 25. Orbit +// 26. Pagination +// 27. Progress Bar +// 28. Reveal +// 29. Slider +// 30. Switch +// 31. Table +// 32. Tabs +// 33. Thumbnail +// 34. Title Bar +// 35. Tooltip +// 36. Top Bar + +@import 'util/util'; + +// 1. Global +// --------- + +$global-font-size: 100%; +$global-width: rem-calc(1200); +$global-lineheight: 1.5; +$foundation-palette: ( + primary: #2199e8, + secondary: #777, + success: #3adb76, + warning: #ffae00, + alert: #ec5840, +); +$light-gray: #e6e6e6; +$medium-gray: #cacaca; +$dark-gray: #8a8a8a; +$black: #0a0a0a; +$white: #fefefe; +$body-background: $white; +$body-font-color: $black; +$body-font-family: 'Helvetica Neue', 'Microsoft Yahei', Helvetica, Roboto, 'WenQuanYi Micro Hei', Arial, sans-serif; +$body-antialiased: true; +$global-margin: 1rem; +$global-padding: 1rem; +$global-weight-normal: normal; +$global-weight-bold: bold; +$global-radius: 0; +$global-text-direction: ltr; +$global-flexbox: false; +$print-transparent-backgrounds: true; + +@include add-foundation-colors; + +// 2. Breakpoints +// -------------- + +$breakpoints: ( + small: 0, + medium: 640px, + large: 1024px, + xlarge: 1200px, + xxlarge: 1440px, +); +$breakpoint-classes: (small medium large); + +// 3. The Grid +// ----------- + +$grid-row-width: $global-width; +$grid-column-count: 12; +$grid-column-gutter: ( + small: 20px, + medium: 30px, +); +$grid-column-align-edge: true; +$block-grid-max: 8; + +// 4. Base Typography +// ------------------ + +$header-font-family: $body-font-family; +$header-font-weight: $global-weight-normal; +$header-font-style: normal; +$font-family-monospace: Consolas, 'Liberation Mono', Courier, monospace; +$header-sizes: ( + small: ( + 'h1': 24, + 'h2': 20, + 'h3': 19, + 'h4': 18, + 'h5': 17, + 'h6': 16, + ), + medium: ( + 'h1': 48, + 'h2': 40, + 'h3': 31, + 'h4': 25, + 'h5': 20, + 'h6': 16, + ), +); +$header-color: inherit; +$header-lineheight: 1.4; +$header-margin-bottom: 0.5rem; +$header-text-rendering: optimizeLegibility; +$small-font-size: 80%; +$header-small-font-color: $medium-gray; +$paragraph-lineheight: 1.6; +$paragraph-margin-bottom: 1rem; +$paragraph-text-rendering: optimizeLegibility; +$code-color: $black; +$code-font-family: $font-family-monospace; +$code-font-weight: $global-weight-normal; +$code-background: $light-gray; +$code-border: 1px solid $medium-gray; +$code-padding: rem-calc(2 5 1); +$anchor-color: $primary-color; +$anchor-color-hover: scale-color($anchor-color, $lightness: -14%); +$anchor-text-decoration: none; +$anchor-text-decoration-hover: none; +$hr-width: $global-width; +$hr-border: 1px solid $medium-gray; +$hr-margin: rem-calc(20) auto; +$list-lineheight: $paragraph-lineheight; +$list-margin-bottom: $paragraph-margin-bottom; +$list-style-type: disc; +$list-style-position: outside; +$list-side-margin: 1.25rem; +$list-nested-side-margin: 1.25rem; +$defnlist-margin-bottom: 1rem; +$defnlist-term-weight: $global-weight-bold; +$defnlist-term-margin-bottom: 0.3rem; +$blockquote-color: $dark-gray; +$blockquote-padding: rem-calc(9 20 0 19); +$blockquote-border: 1px solid $medium-gray; +$cite-font-size: rem-calc(13); +$cite-color: $dark-gray; +$keystroke-font: $font-family-monospace; +$keystroke-color: $black; +$keystroke-background: $light-gray; +$keystroke-padding: rem-calc(2 4 0); +$keystroke-radius: $global-radius; +$abbr-underline: 1px dotted $black; + +// 5. Typography Helpers +// --------------------- + +$lead-font-size: $global-font-size * 1.25; +$lead-lineheight: 1.6; +$subheader-lineheight: 1.4; +$subheader-color: $dark-gray; +$subheader-font-weight: $global-weight-normal; +$subheader-margin-top: 0.2rem; +$subheader-margin-bottom: 0.5rem; +$stat-font-size: 2.5rem; + +// 6. Abide +// -------- + +$abide-inputs: true; +$abide-labels: true; +$input-background-invalid: map-get($foundation-palette, alert); +$form-label-color-invalid: map-get($foundation-palette, alert); +$input-error-color: map-get($foundation-palette, alert); +$input-error-font-size: rem-calc(12); +$input-error-font-weight: $global-weight-bold; + +// 7. Accordion +// ------------ + +$accordion-background: $white; +$accordion-plusminus: true; +$accordion-item-color: foreground($accordion-background, $primary-color); +$accordion-item-background-hover: $light-gray; +$accordion-item-padding: 1.25rem 1rem; +$accordion-content-background: $white; +$accordion-content-border: 1px solid $light-gray; +$accordion-content-color: foreground($accordion-background, $primary-color); +$accordion-content-padding: 1rem; + +// 8. Accordion Menu +// ----------------- + +$accordionmenu-arrows: true; +$accordionmenu-arrow-color: $primary-color; + +// 9. Badge +// -------- + +$badge-background: $primary-color; +$badge-color: foreground($badge-background); +$badge-padding: 0.3em; +$badge-minwidth: 2.1em; +$badge-font-size: 0.6rem; + +// 10. Breadcrumbs +// --------------- + +$breadcrumbs-margin: 0 0 $global-margin 0; +$breadcrumbs-item-font-size: rem-calc(11); +$breadcrumbs-item-color: $primary-color; +$breadcrumbs-item-color-current: $black; +$breadcrumbs-item-color-disabled: $medium-gray; +$breadcrumbs-item-margin: 0.75rem; +$breadcrumbs-item-uppercase: true; +$breadcrumbs-item-slash: true; + +// 11. Button +// ---------- + +$button-padding: 0.85em 1em; +$button-margin: 0 0 $global-margin 0; +$button-fill: solid; +$button-background: $primary-color; +$button-background-hover: scale-color($button-background, $lightness: -15%); +$button-color: $white; +$button-color-alt: $black; +$button-radius: $global-radius; +$button-sizes: ( + tiny: 0.6rem, + small: 0.75rem, + default: 0.9rem, + large: 1.25rem, +); +$button-opacity-disabled: 0.25; + +// 12. Button Group +// ---------------- + +$buttongroup-margin: 1rem; +$buttongroup-spacing: 1px; +$buttongroup-child-selector: '.button'; +$buttongroup-expand-max: 6; + +// 13. Callout +// ----------- + +$callout-background: $white; +$callout-background-fade: 85%; +$callout-border: 1px solid rgba($black, 0.25); +$callout-margin: 0 0 1rem 0; +$callout-padding: 1rem; +$callout-font-color: $body-font-color; +$callout-font-color-alt: $body-background; +$callout-radius: $global-radius; +$callout-link-tint: 30%; + +// 14. Close Button +// ---------------- + +$closebutton-position: right top; +$closebutton-offset-horizontal: 1rem; +$closebutton-offset-vertical: 0.5rem; +$closebutton-size: 2em; +$closebutton-lineheight: 1; +$closebutton-color: $dark-gray; +$closebutton-color-hover: $black; + +// 15. Drilldown +// ------------- + +$drilldown-transition: transform 0.15s linear; +$drilldown-arrows: true; +$drilldown-arrow-color: $primary-color; +$drilldown-background: $white; + +// 16. Dropdown +// ------------ + +$dropdown-padding: 1rem; +$dropdown-border: 1px solid $medium-gray; +$dropdown-font-size: 1rem; +$dropdown-width: 300px; +$dropdown-radius: $global-radius; +$dropdown-sizes: ( + tiny: 100px, + small: 200px, + large: 400px, +); + +// 17. Dropdown Menu +// ----------------- + +$dropdownmenu-arrows: true; +$dropdownmenu-arrow-color: $anchor-color; +$dropdownmenu-min-width: 200px; +$dropdownmenu-background: $white; +$dropdownmenu-border: 1px solid $medium-gray; + +// 18. Flex Video +// -------------- + +$flexvideo-margin-bottom: rem-calc(16); +$flexvideo-ratio: 4 by 3; +$flexvideo-ratio-widescreen: 16 by 9; + +// 19. Forms +// --------- + +$fieldset-border: 1px solid $medium-gray; +$fieldset-padding: rem-calc(20); +$fieldset-margin: rem-calc(18 0); +$legend-padding: rem-calc(0 3); +$form-spacing: rem-calc(16); +$helptext-color: $black; +$helptext-font-size: rem-calc(13); +$helptext-font-style: italic; +$input-prefix-color: $black; +$input-prefix-background: $light-gray; +$input-prefix-border: 1px solid $medium-gray; +$input-prefix-padding: 1rem; +$form-label-color: $black; +$form-label-font-size: rem-calc(14); +$form-label-font-weight: $global-weight-normal; +$form-label-line-height: 1.8; +$select-background: $white; +$select-triangle-color: $dark-gray; +$select-radius: $global-radius; +$input-color: $black; +$input-placeholder-color: $medium-gray; +$input-font-family: inherit; +$input-font-size: rem-calc(16); +$input-background: $white; +$input-background-focus: $white; +$input-background-disabled: $light-gray; +$input-border: 1px solid $medium-gray; +$input-border-focus: 1px solid $dark-gray; +$input-shadow: inset 0 1px 2px rgba($black, 0.1); +$input-shadow-focus: 0 0 5px $medium-gray; +$input-cursor-disabled: not-allowed; +$input-transition: box-shadow 0.5s, border-color 0.25s ease-in-out; +$input-number-spinners: true; +$input-radius: $global-radius; + +// 20. Label +// --------- + +$label-background: $primary-color; +$label-color: foreground($label-background); +$label-font-size: 0.8rem; +$label-padding: 0.33333rem 0.5rem; +$label-radius: $global-radius; + +// 21. Media Object +// ---------------- + +$mediaobject-margin-bottom: $global-margin; +$mediaobject-section-padding: $global-padding; +$mediaobject-image-width-stacked: 100%; + +// 22. Menu +// -------- + +$menu-margin: 0; +$menu-margin-nested: 1rem; +$menu-item-padding: 0.7rem 1rem; +$menu-item-color-active: $white; +$menu-item-background-active: map-get($foundation-palette, primary); +$menu-icon-spacing: 0.25rem; + +// 23. Meter +// --------- + +$meter-height: 1rem; +$meter-radius: $global-radius; +$meter-background: $medium-gray; +$meter-fill-good: $success-color; +$meter-fill-medium: $warning-color; +$meter-fill-bad: $alert-color; + +// 24. Off-canvas +// -------------- + +$offcanvas-size: 250px; +$offcanvas-background: #474747; +$offcanvas-zindex: -1; +$offcanvas-transition-length: 0.5s; +$offcanvas-transition-timing: ease; +$offcanvas-fixed-reveal: true; +$offcanvas-exit-background: rgba($white, 0.25); +$maincontent-class: 'off-canvas-content'; +$maincontent-shadow: 0 0 10px rgba($black, 0.5); + +// 25. Orbit +// --------- + +$orbit-bullet-background: $medium-gray; +$orbit-bullet-background-active: $dark-gray; +$orbit-bullet-diameter: 1.2rem; +$orbit-bullet-margin: 0.1rem; +$orbit-bullet-margin-top: 0.8rem; +$orbit-bullet-margin-bottom: 0.8rem; +$orbit-caption-background: rgba($black, 0.5); +$orbit-caption-padding: 1rem; +$orbit-control-background-hover: rgba($black, 0.5); +$orbit-control-padding: 1rem; +$orbit-control-zindex: 10; + +// 26. Pagination +// -------------- + +$pagination-font-size: rem-calc(14); +$pagination-margin-bottom: $global-margin; +$pagination-item-color: $black; +$pagination-item-padding: rem-calc(3 10); +$pagination-item-spacing: rem-calc(1); +$pagination-radius: $global-radius; +$pagination-item-background-hover: $light-gray; +$pagination-item-background-current: $primary-color; +$pagination-item-color-current: foreground($pagination-item-background-current); +$pagination-item-color-disabled: $medium-gray; +$pagination-ellipsis-color: $black; +$pagination-mobile-items: false; +$pagination-arrows: true; + +// 27. Progress Bar +// ---------------- + +$progress-height: 1rem; +$progress-background: $medium-gray; +$progress-margin-bottom: $global-margin; +$progress-meter-background: $primary-color; +$progress-radius: $global-radius; + +// 28. Reveal +// ---------- + +$reveal-background: $white; +$reveal-width: 600px; +$reveal-max-width: $global-width; +$reveal-padding: $global-padding; +$reveal-border: 1px solid $medium-gray; +$reveal-radius: $global-radius; +$reveal-zindex: 1005; +$reveal-overlay-background: rgba($black, 0.45); + +// 29. Slider +// ---------- + +$slider-width-vertical: 0.5rem; +$slider-transition: all 0.2s ease-in-out; +$slider-height: 0.5rem; +$slider-background: $light-gray; +$slider-fill-background: $medium-gray; +$slider-handle-height: 1.4rem; +$slider-handle-width: 1.4rem; +$slider-handle-background: $primary-color; +$slider-opacity-disabled: 0.25; +$slider-radius: $global-radius; + +// 30. Switch +// ---------- + +$switch-background: $medium-gray; +$switch-background-active: $primary-color; +$switch-height: 2rem; +$switch-height-tiny: 1.5rem; +$switch-height-small: 1.75rem; +$switch-height-large: 2.5rem; +$switch-radius: $global-radius; +$switch-margin: $global-margin; +$switch-paddle-background: $white; +$switch-paddle-offset: 0.25rem; +$switch-paddle-radius: $global-radius; +$switch-paddle-transition: all 0.25s ease-out; + +// 31. Table +// --------- + +$table-background: $white; +$table-color-scale: 5%; +$table-border: 1px solid smart-scale($table-background, $table-color-scale); +$table-padding: rem-calc(8 10 10); +$table-hover-scale: 2%; +$table-row-hover: darken($table-background, $table-hover-scale); +$table-row-stripe-hover: darken($table-background, $table-color-scale + $table-hover-scale); +$table-striped-background: smart-scale($table-background, $table-color-scale); +$table-stripe: even; +$table-head-background: smart-scale($table-background, $table-color-scale / 2); +$table-foot-background: smart-scale($table-background, $table-color-scale); +$table-head-font-color: $body-font-color; +$show-header-for-stacked: false; + +// 32. Tabs +// -------- + +$tab-margin: 0; +$tab-background: $white; +$tab-background-active: $light-gray; +$tab-item-font-size: rem-calc(12); +$tab-item-background-hover: $white; +$tab-item-padding: 1.25rem 1.5rem; +$tab-expand-max: 6; +$tab-content-background: $white; +$tab-content-border: $light-gray; +$tab-content-color: foreground($tab-background, $primary-color); +$tab-content-padding: 1rem; + +// 33. Thumbnail +// ------------- + +$thumbnail-border: solid 4px $white; +$thumbnail-margin-bottom: $global-margin; +$thumbnail-shadow: 0 0 0 1px rgba($black, 0.2); +$thumbnail-shadow-hover: 0 0 6px 1px rgba($primary-color, 0.5); +$thumbnail-transition: box-shadow 200ms ease-out; +$thumbnail-radius: $global-radius; + +// 34. Title Bar +// ------------- + +$titlebar-background: $black; +$titlebar-color: $white; +$titlebar-padding: 0.5rem; +$titlebar-text-font-weight: bold; +$titlebar-icon-color: $white; +$titlebar-icon-color-hover: $medium-gray; +$titlebar-icon-spacing: 0.25rem; + +// 35. Tooltip +// ----------- + +$has-tip-font-weight: $global-weight-bold; +$has-tip-border-bottom: dotted 1px $dark-gray; +$tooltip-background-color: $black; +$tooltip-color: $white; +$tooltip-padding: 0.75rem; +$tooltip-font-size: $small-font-size; +$tooltip-pip-width: 0.75rem; +$tooltip-pip-height: $tooltip-pip-width * 0.866; +$tooltip-radius: $global-radius; + +// 36. Top Bar +// ----------- + +$topbar-padding: 0.5rem; +$topbar-background: $black; +$topbar-submenu-background: $topbar-background; +$topbar-title-spacing: 1rem; +$topbar-input-width: 200px; +$topbar-unstack-breakpoint: medium; + diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index e5fe770..e420cb5 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -1,17 +1,15 @@ -//.inner-wrap { - //min-height: 100%; -//} - +@import 'font-awesome-sprockets'; +@import 'font-awesome'; @import 'foundation_and_overrides'; -@import 'aboutme_welcome'; -@import 'archives'; +@import 'aboutme_welcome'; +@import 'archives'; @import 'markdown'; -@import 'blogs'; -@import 'head'; +@import 'blogs'; +@import 'head'; @import 'qrcodes'; @import 'angularjs'; -@import 'comments'; +@import 'comments'; @import 'highlight'; @import 'footer'; @import 'like_and_weixin'; diff --git a/app/assets/stylesheets/foundation_and_overrides.scss b/app/assets/stylesheets/foundation_and_overrides.scss index 10f5867..f60bbaf 100644 --- a/app/assets/stylesheets/foundation_and_overrides.scss +++ b/app/assets/stylesheets/foundation_and_overrides.scss @@ -1,1194 +1,52 @@ -// -// FOUNDATION SETTINGS -// - -// This is the default html and body font-size for the base rem value. -// $rem-base: 16px; - -// Allows the use of rem-calc() or lower-bound() in your settings -@import "foundation/functions"; - -// $experimental: true; - -// The default font-size is set to 100% of the browser style sheet (usually 16px) -// for compatibility with brower-based text zoom or user-set defaults. - -// Since the typical default browser font-size is 16px, that makes the calculation for grid size. -// If you want your base font-size to be different and not have it affect the grid breakpoints, -// set $rem-base to $base-font-size and make sure $base-font-size is a px value. -$base-font-size: 100%; - -// The $base-line-height is 100% while $base-font-size is 150% -// $base-line-height: 150%; - -// We use this to control whether or not CSS classes come through in the gem files. -// $include-html-classes: true; -// $include-print-styles: true; -// $include-html-global-classes: $include-html-classes; - -// Grid - -// $include-html-grid-classes: $include-html-classes; - -// $row-width: rem-calc(1000); -// $column-gutter: rem-calc(30); -// $total-columns: 12; - -// We use these to control various global styles -// $body-bg: #fff; -// $body-font-color: #222; -// $body-font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; -// $body-font-weight: normal; -// $body-font-style: normal; - -// We use this to control font-smoothing -// $font-smoothing: antialiased; - -// We use these to control text direction settings -// $text-direction: ltr; -// $opposite-direction: right; -// $default-float: left; - -// We use these as default colors throughout -// $primary-color: #008CBA; -// $secondary-color: #e7e7e7; -// $alert-color: #f04124; -// $success-color: #43AC6A; -// $warning-color: #f08a24; -// $info-color: #a0d3e8; - -// We use these to make sure border radius matches unless we want it different. -// $global-radius: 3px; -// $global-rounded: 1000px; - -// We use these to control inset shadow shiny edges and depressions. -// $shiny-edge-size: 0 1px 0; -// $shiny-edge-color: rgba(#fff, .5); -// $shiny-edge-active-color: rgba(#000, .2); - -// Media Query Ranges -// $small-range: (0em, 40em); -// $medium-range: (40.063em, 64em); -// $large-range: (64.063em, 90em); -// $xlarge-range: (90.063em, 120em); -// $xxlarge-range: (120.063em); - -// $screen: "only screen"; - -// $landscape: "#{$screen} and (orientation: landscape)"; -// $portrait: "#{$screen} and (orientation: portrait)"; - -// $small-up: $screen; -// $small-only: "#{$screen} and (max-width: #{upper-bound($small-range)})"; - -// $medium-up: "#{$screen} and (min-width:#{lower-bound($medium-range)})"; -// $medium-only: "#{$screen} and (min-width:#{lower-bound($medium-range)}) and (max-width:#{upper-bound($medium-range)})"; - -// $large-up: "#{$screen} and (min-width:#{lower-bound($large-range)})"; -// $large-only: "#{$screen} and (min-width:#{lower-bound($large-range)}) and (max-width:#{upper-bound($large-range)})"; - -// $xlarge-up: "#{$screen} and (min-width:#{lower-bound($xlarge-range)})"; -// $xlarge-only: "#{$screen} and (min-width:#{lower-bound($xlarge-range)}) and (max-width:#{upper-bound($xlarge-range)})"; - -// $xxlarge-up: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)})"; -// $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (max-width:#{upper-bound($xxlarge-range)})"; - -// Legacy -// $small: $medium-up; -// $medium: $medium-up; -// $large: $large-up; - -//We use this as cursors values for enabling the option of having custom cursors in the whole site's stylesheet -// $cursor-crosshair-value: crosshair; -// $cursor-default-value: default; -// $cursor-pointer-value: pointer; -// $cursor-help-value: help; -// $cursor-text-value: text; - -// Accordion - -// $include-html-accordion-classes: $include-html-classes; - -// $accordion-navigation-padding: rem-calc(16); -// $accordion-navigation-bg-color: #efefef ; -// $accordion-navigation-hover-bg-color: scale-color($accordion-navigation-bg-color, $lightness: -5%); -// $accordion-navigation-active-bg-color: scale-color($accordion-navigation-bg-color, $lightness: -3%); -// $accordion-navigation-font-color: #222; -// $accordion-navigation-font-size: rem-calc(16); -// $accordion-navigation-font-family: $body-font-family; - -// $accordion-content-padding: $column-gutter/2; -// $accordion-content-active-bg-color: #fff; - -// Alert Boxes - -// $include-html-alert-classes: $include-html-classes; - -// We use this to control alert padding. -// $alert-padding-top: rem-calc(14); -// $alert-padding-default-float: $alert-padding-top; -// $alert-padding-opposite-direction: $alert-padding-top + rem-calc(10); -// $alert-padding-bottom: $alert-padding-top; - -// We use these to control text style. -// $alert-font-weight: normal; -// $alert-font-size: rem-calc(13); -// $alert-font-color: #fff; -// $alert-font-color-alt: scale-color($secondary-color, $lightness: -66%); - -// We use this for close hover effect. -// $alert-function-factor: -14%; - -// We use these to control border styles. -// $alert-border-style: solid; -// $alert-border-width: 1px; -// $alert-border-color: scale-color($primary-color, $lightness: $alert-function-factor); -// $alert-bottom-margin: rem-calc(20); - -// We use these to style the close buttons -// $alert-close-color: #333; -// $alert-close-top: 50%; -// $alert-close-position: rem-calc(5); -// $alert-close-font-size: rem-calc(22); -// $alert-close-opacity: 0.3; -// $alert-close-opacity-hover: 0.5; -// $alert-close-padding: 9px 6px 4px; - -// We use this to control border radius -// $alert-radius: $global-radius; - -// Block Grid - -// $include-html-grid-classes: $include-html-classes; - -// We use this to control the maximum number of block grid elements per row -// $block-grid-elements: 12; -// $block-grid-default-spacing: rem-calc(20); - -// Enables media queries for block-grid classes. Set to false if writing semantic HTML. -// $block-grid-media-queries: true; - -// Breadcrumbs - -// $include-html-nav-classes: $include-html-classes; - -// We use this to set the background color for the breadcrumb container. -// $crumb-bg: scale-color($secondary-color, $lightness: 55%); - -// We use these to set the padding around the breadcrumbs. -// $crumb-padding: rem-calc(9 14 9); -// $crumb-side-padding: rem-calc(12); - -// We use these to control border styles. -// $crumb-function-factor: -10%; -// $crumb-border-size: 1px; -// $crumb-border-style: solid; -// $crumb-border-color: scale-color($crumb-bg, $lightness: $crumb-function-factor); -// $crumb-radius: $global-radius; - -// We use these to set various text styles for breadcrumbs. -// $crumb-font-size: rem-calc(11); -// $crumb-font-color: $primary-color; -// $crumb-font-color-current: #333; -// $crumb-font-color-unavailable: #999; -// $crumb-font-transform: uppercase; -// $crumb-link-decor: underline; - -// We use these to control the slash between breadcrumbs -// $crumb-slash-color: #aaa; -// $crumb-slash: "/"; - -// -// BUTTONS -// - -// $include-html-button-classes: $include-html-classes; - -// We use these to build padding for buttons. -// $button-tny: rem-calc(10); -// $button-sml: rem-calc(14); -// $button-med: rem-calc(16); -// $button-lrg: rem-calc(18); - -// We use this to control the display property. -// $button-display: inline-block; -// $button-margin-bottom: rem-calc(20); - -// We use these to control button text styles. -// $button-font-family: $body-font-family; -// $button-font-color: #fff; -// $button-font-color-alt: #333; -// $button-font-tny: rem-calc(11); -// $button-font-sml: rem-calc(13); -// $button-font-med: rem-calc(16); -// $button-font-lrg: rem-calc(20); -// $button-font-weight: normal; -// $button-font-align: center; - -// We use these to control various hover effects. -// $button-function-factor: 5%; - -// We use these to control button border styles. -// $button-border-width: 1px; -// $button-border-style: solid; - -// We use this to set the default radius used throughout the core. -// $button-radius: $global-radius; -// $button-round: $global-rounded; - -// We use this to set default opacity for disabled buttons. -// $button-disabled-opacity: 0.7; - -// Button Groups - -// $include-html-button-classes: $include-html-classes; - -// Sets the margin for the right side by default, and the left margin if right-to-left direction is used -// $button-bar-margin-opposite: rem-calc(10); -// $button-group-border-width: 1px; - -// Clearing - -// $include-html-clearing-classes: $include-html-classes; - -// We use these to set the background colors for parts of Clearing. -// $clearing-bg: #333; -// $clearing-caption-bg: $clearing-bg; -// $clearing-carousel-bg: rgba (51,51,51,0.8); -// $clearing-img-bg: $clearing-bg; - -// We use these to style the close button -// $clearing-close-color: #ccc; -// $clearing-close-size: 30px; - -// We use these to style the arrows -// $clearing-arrow-size: 12px; -// $clearing-arrow-color: $clearing-close-color; - -// We use these to style captions -// $clearing-caption-font-color: #ccc; -// $clearing-caption-font-size: 0.875em; -// $clearing-caption-padding: 10px 30px 20px; - -// We use these to make the image and carousel height and style -// $clearing-active-img-height: 85%; -// $clearing-carousel-height: 120px; -// $clearing-carousel-thumb-width: 120px; -// $clearing-carousel-thumb-active-border: 1px solid rgb(255,255,255); - -// Dropdown - -// $include-html-dropdown-classes: $include-html-classes; - -// We use these to controls height and width styles. -// $f-dropdown-max-width: 200px; -// $f-dropdown-height: auto; -// $f-dropdown-max-height: none; -// $f-dropdown-margin-top: 2px; - -// We use this to control the background color -// $f-dropdown-bg: #fff; - -// We use this to set the border styles for dropdowns. -// $f-dropdown-border-style: solid; -// $f-dropdown-border-width: 1px; -// $f-dropdown-border-color: scale-color(#fff, $lightness: -20%); - -// We use these to style the triangle pip. -// $f-dropdown-triangle-size: 6px; -// $f-dropdown-triangle-color: #fff; -// $f-dropdown-triangle-side-offset: 10px; - -// We use these to control styles for the list elements. -// $f-dropdown-list-style: none; -// $f-dropdown-font-color: #555; -// $f-dropdown-font-size: rem-calc(14); -// $f-dropdown-list-padding: rem-calc(5, 10); -// $f-dropdown-line-height: rem-calc(18); -// $f-dropdown-list-hover-bg: #eeeeee ; -// $dropdown-mobile-default-float: 0; - -// We use this to control the styles for when the dropdown has custom content. -// $f-dropdown-content-padding: rem-calc(20); - -// Dropdown Buttons - -// $include-html-button-classes: $include-html-classes; - -// We use these to set the color of the pip in dropdown buttons -// $dropdown-button-pip-color: #fff; -// $dropdown-button-pip-color-alt: #333; - -// $button-pip-tny: rem-calc(6); -// $button-pip-sml: rem-calc(7); -// $button-pip-med: rem-calc(9); -// $button-pip-lrg: rem-calc(11); - -// We use these to style tiny dropdown buttons -// $dropdown-button-padding-tny: $button-pip-tny * 7; -// $dropdown-button-pip-size-tny: $button-pip-tny; -// $dropdown-button-pip-opposite-tny: $button-pip-tny * 3; -// $dropdown-button-pip-top-tny: -$button-pip-tny / 2 + rem-calc(1); - -// We use these to style small dropdown buttons -// $dropdown-button-padding-sml: $button-pip-sml * 7; -// $dropdown-button-pip-size-sml: $button-pip-sml; -// $dropdown-button-pip-opposite-sml: $button-pip-sml * 3; -// $dropdown-button-pip-top-sml: -$button-pip-sml / 2 + rem-calc(1); - -// We use these to style medium dropdown buttons -// $dropdown-button-padding-med: $button-pip-med * 6 + rem-calc(3); -// $dropdown-button-pip-size-med: $button-pip-med - rem-calc(3); -// $dropdown-button-pip-opposite-med: $button-pip-med * 2.5; -// $dropdown-button-pip-top-med: -$button-pip-med / 2 + rem-calc(2); - -// We use these to style large dropdown buttons -// $dropdown-button-padding-lrg: $button-pip-lrg * 5 + rem-calc(3); -// $dropdown-button-pip-size-lrg: $button-pip-lrg - rem-calc(6); -// $dropdown-button-pip-opposite-lrg: $button-pip-lrg * 2.5; -// $dropdown-button-pip-top-lrg: -$button-pip-lrg / 2 + rem-calc(3); - -// Flex Video - -// $include-html-media-classes: $include-html-classes; - -// We use these to control video container padding and margins -// $flex-video-padding-top: rem-calc(25); -// $flex-video-padding-bottom: 67.5%; -// $flex-video-margin-bottom: rem-calc(16); - -// We use this to control widescreen bottom padding -// $flex-video-widescreen-padding-bottom: 57.25%; - -// Forms - -// $include-html-form-classes: $include-html-classes; - -// We use this to set the base for lots of form spacing and positioning styles -// $form-spacing: rem-calc(16); - -// We use these to style the labels in different ways -// $form-label-pointer: pointer; -// $form-label-font-size: rem-calc(14); -// $form-label-font-weight: normal; -// $form-label-font-color: scale-color(#000, $lightness: 30%); -// $form-label-bottom-margin: rem-calc(8); -// $input-font-family: inherit; -// $input-font-color: rgba(0,0,0,0.75); -// $input-font-size: rem-calc(14); -// $input-bg-color: #fff; -// $input-focus-bg-color: scale-color(#fff, $lightness: -2%); -// $input-border-color: scale-color(#fff, $lightness: -20%); -// $input-focus-border-color: scale-color(#fff, $lightness: -40%); -// $input-border-style: solid; -// $input-border-width: 1px; -// $input-disabled-bg: #ddd; -// $input-box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); -// $input-include-glowing-effect: true; - -// We use these to style the fieldset border and spacing. -// $fieldset-border-style: solid; -// $fieldset-border-width: 1px; -// $fieldset-border-color: #ddd; -// $fieldset-padding: rem-calc(20); -// $fieldset-margin: rem-calc(18 0); - -// We use these to style the legends when you use them -// $legend-bg: #fff; -// $legend-font-weight: bold; -// $legend-padding: rem-calc(0 3); - -// We use these to style the prefix and postfix input elements -// $input-prefix-bg: scale-color(#fff, $lightness: -5%); -// $input-prefix-border-color: scale-color(#fff, $lightness: -20%); -// $input-prefix-border-size: 1px; -// $input-prefix-border-type: solid; -// $input-prefix-overflow: hidden; -// $input-prefix-font-color: #333; -// $input-prefix-font-color-alt: #fff; - -// We use these to style the error states for inputs and labels -// $input-error-message-padding: rem-calc(6 9 9); -// $input-error-message-top: -1px; -// $input-error-message-font-size: rem-calc(12); -// $input-error-message-font-weight: normal; -// $input-error-message-font-style: italic; -// $input-error-message-font-color: #fff; -// $input-error-message-font-color-alt: #333; - -// We use this to style the glowing effect of inputs when focused -// $glowing-effect-fade-time: 0.45s; -// $glowing-effect-color: $input-focus-border-color; - -// Select variables -// $select-bg-color: #fafafa; - -// Inline Lists - -// $include-html-inline-list-classes: $include-html-classes; - -// We use this to control the margins and padding of the inline list. -// $inline-list-top-margin: 0; -// $inline-list-opposite-margin: 0; -// $inline-list-bottom-margin: rem-calc(17); -// $inline-list-default-float-margin: rem-calc(-22); - -// $inline-list-padding: 0; - -// We use this to control the overflow of the inline list. -// $inline-list-overflow: hidden; - -// We use this to control the list items -// $inline-list-display: block; - -// We use this to control any elments within list items -// $inline-list-children-display: block; - -// Joyride - -// $include-html-joyride-classes: $include-html-classes; - -// Controlling default Joyride styles -// $joyride-tip-bg: #333; -// $joyride-tip-default-width: 300px; -// $joyride-tip-padding: rem-calc(18 20 24); -// $joyride-tip-border: solid 1px #555; -// $joyride-tip-radius: 4px; -// $joyride-tip-position-offset: 22px; - -// Here, we're setting the tip dont styles -// $joyride-tip-font-color: #fff; -// $joyride-tip-font-size: rem-calc(14); -// $joyride-tip-header-weight: bold; - -// This changes the nub size -// $joyride-tip-nub-size: 10px; - -// This adjusts the styles for the timer when its enabled -// $joyride-tip-timer-width: 50px; -// $joyride-tip-timer-height: 3px; -// $joyride-tip-timer-color: #666; - -// This changes up the styles for the close button -// $joyride-tip-close-color: #777; -// $joyride-tip-close-size: 24px; -// $joyride-tip-close-weight: normal; - -// When Joyride is filling the screen, we use this style for the bg -// $joyride-screenfill: rgba(0,0,0,0.5); - -// Keystrokes - -// $include-html-type-classes: $include-html-classes; - -// We use these to control text styles. -// $keystroke-font: "Consolas", "Menlo", "Courier", monospace; -// $keystroke-font-size: rem-calc(14); -// $keystroke-font-color: #222; -// $keystroke-font-color-alt: #fff; -// $keystroke-function-factor: -7%; - -// We use this to control keystroke padding. -// $keystroke-padding: rem-calc(2 4 0); - -// We use these to control background and border styles. -// $keystroke-bg: scale-color(#fff, $lightness: $keystroke-function-factor); -// $keystroke-border-style: solid; -// $keystroke-border-width: 1px; -// $keystroke-border-color: scale-color($keystroke-bg, $lightness: $keystroke-function-factor); -// $keystroke-radius: $global-radius; - -// Labels - -// $include-html-label-classes: $include-html-classes; - -// We use these to style the labels -// $label-padding: rem-calc(4 8 6); -// $label-radius: $global-radius; - -// We use these to style the label text -// $label-font-sizing: rem-calc(11); -// $label-font-weight: normal; -// $label-font-color: #333; -// $label-font-color-alt: #fff; -// $label-font-family: $body-font-family; - -// Magellan - -// $include-html-magellan-classes: $include-html-classes; - -// $magellan-bg: #fff; -// $magellan-padding: 10px; - -// Off-canvas - -// $tabbar-bg: #333; -// $tabbar-height: rem-calc(45); -// $tabbar-line-height: $tabbar-height; -// $tabbar-color: #FFF; -// $tabbar-middle-padding: 0 rem-calc(10); - -// Off Canvas Divider Styles -// $tabbar-right-section-border: solid 1px scale-color($tabbar-bg, $lightness: 13%); -// $tabbar-left-section-border: solid 1px scale-color($tabbar-bg, $lightness: -50%); - -// Off Canvas Tab Bar Headers -// $tabbar-header-color: #FFF; -// $tabbar-header-weight: bold; -// $tabbar-header-line-height: $tabbar-height; -// $tabbar-header-margin: 0; - -// Off Canvas Menu Variables -// $off-canvas-width: 250px; -// $off-canvas-bg: #333; - -// Off Canvas Menu List Variables -// $off-canvas-label-padding: 0.3rem rem-calc(15); -// $off-canvas-label-color: #999; -// $off-canvas-label-text-transform: uppercase; -// $off-canvas-label-font-weight: bold; -// $off-canvas-label-bg: #444; -// $off-canvas-label-border-top: 1px solid scale-color(#444, $lightness: 14%); -// $off-canvas-label-border-bottom: none; -// $off-canvas-label-margin:0; -// $off-canvas-link-padding: rem-calc(10, 15); -// $off-canvas-link-color: rgba(#FFF, 0.7); -// $off-canvas-link-border-bottom: 1px solid scale-color($off-canvas-bg, $lightness: -25%); - -// Off Canvas Menu Icon Variables -// $tabbar-menu-icon-color: #FFF; -// $tabbar-menu-icon-hover: scale-color($tabbar-menu-icon-color, $lightness: -30%); - -// $tabbar-menu-icon-text-indent: rem-calc(35); -// $tabbar-menu-icon-width: $tabbar-height; -// $tabbar-menu-icon-height: $tabbar-height; -// $tabbar-menu-icon-line-height: rem-calc(33); -// $tabbar-menu-icon-padding: 0; - -// $tabbar-hamburger-icon-width: rem-calc(16); -// $tabbar-hamburger-icon-left: rem-calc(13); -// $tabbar-hamburger-icon-top: rem-calc(5); - -// Off Canvas Back-Link Overlay -// $off-canvas-overlay-transition: background 300ms ease; -// $off-canvas-overlay-cursor: pointer; -// $off-canvas-overlay-box-shadow: -4px 0 4px rgba(#000, 0.5), 4px 0 4px rgba(#000, 0.5); -// $off-canvas-overlay-background: rgba(#FFF, 0.2); -// $off-canvas-overlay-background-hover: rgba(#FFF, 0.05); - -// Transition Variables -// $menu-slide: "transform 500ms ease"; - -// Orbit - -// $include-html-orbit-classes: $include-html-classes; - -// We use these to control the caption styles -// $orbit-container-bg: none; -// $orbit-caption-bg: rgba(51,51,51, 0.8); -// $orbit-caption-font-color: #fff; -// $orbit-caption-font-size: rem-calc(14); -// $orbit-caption-position: "bottom"; // Supported values: "bottom", "under" -// $orbit-caption-padding: rem-calc(10 14); -// $orbit-caption-height: auto; - -// We use these to control the left/right nav styles -// $orbit-nav-bg: none; -// $orbit-nav-bg-hover: rgba(0,0,0,0.3); -// $orbit-nav-arrow-color: #fff; -// $orbit-nav-arrow-color-hover: #fff; - -// We use these to control the timer styles -// $orbit-timer-bg: rgba(255,255,255,0.3); -// $orbit-timer-show-progress-bar: true; - -// We use these to control the bullet nav styles -// $orbit-bullet-nav-color: #ccc; -// $orbit-bullet-nav-color-active: #999; -// $orbit-bullet-radius: rem-calc(9); - -// We use these to controls the style of slide numbers -// $orbit-slide-number-bg: rgba(0,0,0,0); -// $orbit-slide-number-font-color: #fff; -// $orbit-slide-number-padding: rem-calc(5); - -// Graceful Loading Wrapper and preloader -// $wrapper-class: "slideshow-wrapper"; -// $preloader-class: "preloader"; - -// Pagination - -// $include-html-nav-classes: $include-html-classes; - -// We use these to control the pagination container -// $pagination-height: rem-calc(24); -// $pagination-margin: rem-calc(-5); - -// We use these to set the list-item properties -// $pagination-li-float: $default-float; -// $pagination-li-height: rem-calc(24); -// $pagination-li-font-color: #222; -// $pagination-li-font-size: rem-calc(14); -// $pagination-li-margin: rem-calc(5); - -// We use these for the pagination anchor links -// $pagination-link-pad: rem-calc(1 10 1); -// $pagination-link-font-color: #999; -// $pagination-link-active-bg: scale-color(#fff, $lightness: -10%); - -// We use these for disabled anchor links -// $pagination-link-unavailable-cursor: default; -// $pagination-link-unavailable-font-color: #999; -// $pagination-link-unavailable-bg-active: transparent; - -// We use these for currently selected anchor links -// $pagination-link-current-background: $primary-color; -// $pagination-link-current-font-color: #fff; -// $pagination-link-current-font-weight: bold; -// $pagination-link-current-cursor: default; -// $pagination-link-current-active-bg: $primary-color; - -// Panels - -// $include-html-panel-classes: $include-html-classes; - -// We use these to control the background and border styles -// $panel-bg: scale-color(#fff, $lightness: -5%); -// $panel-border-style: solid; -// $panel-border-size: 1px; - -// We use this % to control how much we darken things on hover -// $panel-function-factor: -11%; -// $panel-border-color: scale-color($panel-bg, $lightness: $panel-function-factor); - -// We use these to set default inner padding and bottom margin -// $panel-margin-bottom: rem-calc(20); -// $panel-padding: rem-calc(20); - -// We use these to set default font colors -// $panel-font-color: #333; -// $panel-font-color-alt: #fff; - -// $panel-header-adjust: true; -// $callout-panel-link-color: $primary-color; - -// Pricing Tables - -// $include-html-pricing-classes: $include-html-classes; - -// We use this to control the border color -// $price-table-border: solid 1px #ddd; - -// We use this to control the bottom margin of the pricing table -// $price-table-margin-bottom: rem-calc(20); - -// We use these to control the title styles -// $price-title-bg: #333; -// $price-title-padding: rem-calc(15 20); -// $price-title-align: center; -// $price-title-color: #eee; -// $price-title-weight: normal; -// $price-title-size: rem-calc(16); -// $price-title-font-family: $body-font-family; - -// We use these to control the price styles -// $price-money-bg: #f6f6f6 ; -// $price-money-padding: rem-calc(15 20); -// $price-money-align: center; -// $price-money-color: #333; -// $price-money-weight: normal; -// $price-money-size: rem-calc(32); -// $price-money-font-family: $body-font-family; - - -// We use these to control the description styles -// $price-bg: #fff; -// $price-desc-color: #777; -// $price-desc-padding: rem-calc(15); -// $price-desc-align: center; -// $price-desc-font-size: rem-calc(12); -// $price-desc-weight: normal; -// $price-desc-line-height: 1.4; -// $price-desc-bottom-border: dotted 1px #ddd; - -// We use these to control the list item styles -// $price-item-color: #333; -// $price-item-padding: rem-calc(15); -// $price-item-align: center; -// $price-item-font-size: rem-calc(14); -// $price-item-weight: normal; -// $price-item-bottom-border: dotted 1px #ddd; - -// We use these to control the CTA area styles -// $price-cta-bg: #fff; -// $price-cta-align: center; -// $price-cta-padding: rem-calc(20 20 0); - -// Progress Meters - -// $include-html-media-classes: $include-html-classes; - -// We use this to se the prog bar height -// $progress-bar-height: rem-calc(25); -// $progress-bar-color: #f6f6f6 ; - -// We use these to control the border styles -// $progress-bar-border-color: scale-color(#fff, $lightness: -20%); -// $progress-bar-border-size: 1px; -// $progress-bar-border-style: solid; -// $progress-bar-border-radius: $global-radius; - -// We use these to control the margin & padding -// $progress-bar-pad: rem-calc(2); -// $progress-bar-margin-bottom: rem-calc(10); - -// We use these to set the meter colors -// $progress-meter-color: $primary-color; -// $progress-meter-secondary-color: $secondary-color; -// $progress-meter-success-color: $success-color; -// $progress-meter-alert-color: $alert-color; - -// Reveal - -// $include-html-reveal-classes: $include-html-classes; - -// We use these to control the style of the reveal overlay. -// $reveal-overlay-bg: rgba(#000, .45); -// $reveal-overlay-bg-old: #000; - -// We use these to control the style of the modal itself. -// $reveal-modal-bg: #fff; -// $reveal-position-top: 50px; -// $reveal-default-width: 80%; -// $reveal-modal-padding: rem-calc(20); -// $reveal-box-shadow: 0 0 10px rgba(#000,.4); - -// We use these to style the reveal close button -// $reveal-close-font-size: rem-calc(22); -// $reveal-close-top: rem-calc(8); -// $reveal-close-side: rem-calc(11); -// $reveal-close-color: #aaa; -// $reveal-close-weight: bold; - -// We use these to control the modal border -// $reveal-border-style: solid; -// $reveal-border-width: 1px; -// $reveal-border-color: #666; - -// $reveal-modal-class: "reveal-modal"; -// $close-reveal-modal-class: "close-reveal-modal"; - -// Side Nav - -// $include-html-nav-classes: $include-html-classes; - -// We use this to control padding. -// $side-nav-padding: rem-calc(14 0); - -// We use these to control list styles. -// $side-nav-list-type: none; -// $side-nav-list-position: inside; -// $side-nav-list-margin: rem-calc(0 0 7 0); - -// We use these to control link styles. -// $side-nav-link-color: $primary-color; -// $side-nav-link-color-active: scale-color(#000, $lightness: 30%); -// $side-nav-font-size: rem-calc(14); -// $side-nav-font-weight: normal; -// $side-nav-font-family: $body-font-family; -// $side-nav-active-font-family: $side-nav-font-family; - - - -// We use these to control border styles -// $side-nav-divider-size: 1px; -// $side-nav-divider-style: solid; -// $side-nav-divider-color: scale-color(#fff, $lightness: -10%); - -// Split Buttons - -// $include-html-button-classes: $include-html-classes; - -// We use these to control different shared styles for Split Buttons -// $split-button-function-factor: 10%; -// $split-button-pip-color: #fff; -// $split-button-pip-color-alt: #333; -// $split-button-active-bg-tint: rgba(0,0,0,0.1); - -// We use these to control tiny split buttons -// $split-button-padding-tny: $button-pip-tny * 10; -// $split-button-span-width-tny: $button-pip-tny * 6; -// $split-button-pip-size-tny: $button-pip-tny; -// $split-button-pip-top-tny: $button-pip-tny * 2; -// $split-button-pip-default-float-tny: rem-calc(-6); - -// We use these to control small split buttons -// $split-button-padding-sml: $button-pip-sml * 10; -// $split-button-span-width-sml: $button-pip-sml * 6; -// $split-button-pip-size-sml: $button-pip-sml; -// $split-button-pip-top-sml: $button-pip-sml * 1.5; -// $split-button-pip-default-float-sml: rem-calc(-6); - -// We use these to control medium split buttons -// $split-button-padding-med: $button-pip-med * 9; -// $split-button-span-width-med: $button-pip-med * 5.5; -// $split-button-pip-size-med: $button-pip-med - rem-calc(3); -// $split-button-pip-top-med: $button-pip-med * 1.5; -// $split-button-pip-default-float-med: rem-calc(-6); - -// We use these to control large split buttons -// $split-button-padding-lrg: $button-pip-lrg * 8; -// $split-button-span-width-lrg: $button-pip-lrg * 5; -// $split-button-pip-size-lrg: $button-pip-lrg - rem-calc(6); -// $split-button-pip-top-lrg: $button-pip-lrg + rem-calc(5); -// $split-button-pip-default-float-lrg: rem-calc(-6); - -// Sub Nav - -// $include-html-nav-classes: $include-html-classes; - -// We use these to control margin and padding -// $sub-nav-list-margin: rem-calc(-4 0 18); -// $sub-nav-list-padding-top: rem-calc(4); - -// We use this to control the definition -// $sub-nav-font-family: $body-font-family; -// $sub-nav-font-size: rem-calc(14); -// $sub-nav-font-color: #999; -// $sub-nav-font-weight: normal; -// $sub-nav-text-decoration: none; -// $sub-nav-border-radius: 3px; -// $sub-nav-font-color-hover: scale-color($sub-nav-font-color, $lightness: -25%); - - -// We use these to control the active item styles - -// $sub-nav-active-font-weight: normal; -// $sub-nav-active-bg: $primary-color; -// $sub-nav-active-bg-hover: scale-color($sub-nav-active-bg, $lightness: -14%); -// $sub-nav-active-color: #fff; -// $sub-nav-active-padding: rem-calc(3 16); -// $sub-nav-active-cursor: default; - -// $sub-nav-item-divider: ""; -// $sub-nav-item-divider-margin: rem-calc(12); - -// -// SWITCH -// - -// $include-html-form-classes: $include-html-classes; - -// Controlling border styles and background colors for the switch container -// $switch-border-color: scale-color(#fff, $lightness: -20%); -// $switch-border-style: solid; -// $switch-border-width: 1px; -// $switch-bg: #fff; - -// We use these to control the switch heights for our default classes -// $switch-height-tny: 22px; -// $switch-height-sml: 28px; -// $switch-height-med: 36px; -// $switch-height-lrg: 44px; -// $switch-bottom-margin: rem-calc(20); - -// We use these to control default font sizes for our classes. -// $switch-font-size-tny: 11px; -// $switch-font-size-sml: 12px; -// $switch-font-size-med: 14px; -// $switch-font-size-lrg: 17px; -// $switch-label-side-padding: 6px; - -// We use these to style the switch-paddle -// $switch-paddle-bg: #fff; -// $switch-paddle-fade-to-color: scale-color($switch-paddle-bg, $lightness: -10%); -// $switch-paddle-border-color: scale-color($switch-paddle-bg, $lightness: -35%); -// $switch-paddle-border-width: 1px; -// $switch-paddle-border-style: solid; -// $switch-paddle-transition-speed: .1s; -// $switch-paddle-transition-ease: ease-out; -// $switch-positive-color: scale-color($success-color, $lightness: 94%); -// $switch-negative-color: #f5f5f5; - -// Outline Style for tabbing through switches -// $switch-label-outline: 1px dotted #888; - -// Tables - -// $include-html-table-classes: $include-html-classes; - -// These control the background color for the table and even rows -// $table-bg: #fff; -// $table-even-row-bg: #f9f9f9 ; - -// These control the table cell border style -// $table-border-style: solid; -// $table-border-size: 1px; -// $table-border-color: #ddd; - -// These control the table head styles -// $table-head-bg: #f5f5f5 ; -// $table-head-font-size: rem-calc(14); -// $table-head-font-color: #222; -// $table-head-font-weight: bold; -// $table-head-padding: rem-calc(8 10 10); - -// These control the row padding and font styles -// $table-row-padding: rem-calc(9 10); -// $table-row-font-size: rem-calc(14); -// $table-row-font-color: #222; -// $table-line-height: rem-calc(18); - -// These are for controlling the display and margin of tables -// $table-display: table-cell; -// $table-margin-bottom: rem-calc(20); - -// -// TABS -// - -// $include-html-tabs-classes: $include-html-classes; - -// $tabs-navigation-padding: rem-calc(16); -$tabs-navigation-bg-color: #fff; -$tabs-navigation-active-bg-color: #eee; -$tabs-navigation-hover-bg-color: scale-color($tabs-navigation-bg-color, $lightness: -3%); -// $tabs-navigation-font-color: #222; -// $tabs-navigation-font-size: rem-calc(16); -// $tabs-navigation-font-family: $body-font-family; - -// $tabs-content-margin-bottom: rem-calc(24); -// $tabs-content-padding: $column-gutter/2; - -// $tabs-vertical-navigation-margin-bottom: 1.25rem; - -// -// THUMBNAILS -// - -// $include-html-media-classes: $include-html-classes; - -// We use these to control border styles -// $thumb-border-style: solid; -// $thumb-border-width: 4px; -// $thumb-border-color: #fff; -// $thumb-box-shadow: 0 0 0 1px rgba(#000,.2); -// $thumb-box-shadow-hover: 0 0 6px 1px rgba($primary-color,0.5); - -// Radius and transition speed for thumbs -// $thumb-radius: $global-radius; -// $thumb-transition-speed: 200ms; - -// -// TOOLTIPS -// - -// $include-html-tooltip-classes: $include-html-classes; - -// $has-tip-border-bottom: dotted 1px #ccc; -// $has-tip-font-weight: bold; -// $has-tip-font-color: #333; -// $has-tip-border-bottom-hover: dotted 1px scale-color($primary-color, $lightness: -55%); -// $has-tip-font-color-hover: $primary-color; -// $has-tip-cursor-type: help; - -// $tooltip-padding: rem-calc(12); -// $tooltip-bg: #333; -// $tooltip-font-size: rem-calc(14); -// $tooltip-font-weight: normal; -// $tooltip-font-color: #fff; -// $tooltip-line-height: 1.3; -// $tooltip-close-font-size: rem-calc(10); -// $tooltip-close-font-weight: normal; -// $tooltip-close-font-color: #777; -// $tooltip-font-size-sml: rem-calc(14); -// $tooltip-radius: $global-radius; -// $tooltip-pip-size: 5px; - -// -// TOP BAR -// - -// $include-html-top-bar-classes: $include-html-classes; - -// Background color for the top bar -// $topbar-bg-color: #333; -// $topbar-bg: $topbar-bg-color; - -// Height and margin -// $topbar-height: 45px; -// $topbar-margin-bottom: 0; - -// Controlling the styles for the title in the top bar -// $topbar-title-weight: normal; -// $topbar-title-font-size: rem-calc(17); - -// Style the top bar dropdown elements -// $topbar-dropdown-bg: #333; -// $topbar-dropdown-link-color: #fff; -// $topbar-dropdown-link-bg: #333; -// $topbar-dropdown-link-weight: normal; -// $topbar-dropdown-toggle-size: 5px; -// $topbar-dropdown-toggle-color: #fff; -// $topbar-dropdown-toggle-alpha: 0.4; - -// Set the link colors and styles for top-level nav -// $topbar-link-color: #fff; -// $topbar-link-color-hover: #fff; -// $topbar-link-color-active: #fff; -// $topbar-link-weight: normal; -// $topbar-link-font-size: rem-calc(13); -// $topbar-link-hover-lightness: -10%; // Darken by 10% -// $topbar-link-bg-hover: #272727 ; -// $topbar-link-bg-active: $primary-color; -// $topbar-link-bg-active-hover: scale-color($primary-color, $lightness: -14%); -// $topbar-link-font-family: $body-font-family; - -// $topbar-button-font-size: 0.75rem; - -// $topbar-dropdown-label-color: #777; -// $topbar-dropdown-label-text-transform: uppercase; -// $topbar-dropdown-label-font-weight: bold; -// $topbar-dropdown-label-font-size: rem-calc(10); -// $topbar-dropdown-label-bg: #333; - -// Top menu icon styles -// $topbar-menu-link-transform: uppercase; -// $topbar-menu-link-font-size: rem-calc(13); -// $topbar-menu-link-weight: bold; -// $topbar-menu-link-color: #fff; -// $topbar-menu-icon-color: #fff; -// $topbar-menu-link-color-toggled: #888; -// $topbar-menu-icon-color-toggled: #888; - -// Transitions and breakpoint styles -// $topbar-transition-speed: 300ms; -// Using rem-calc for the below breakpoint causes issues with top bar -// $topbar-breakpoint: #{upper-bound($medium-range)}; // Change to 9999px for always mobile layout -// $topbar-media-query: "only screen and (min-width: #{upper-bound($medium-range)})"; - -// Divider Styles -// $topbar-divider-border-bottom: solid 1px scale-color($topbar-bg-color, $lightness: 13%); -// $topbar-divider-border-top: solid 1px scale-color($topbar-bg-color, $lightness: -50%); - -// Sticky Class -// $topbar-sticky-class: ".sticky"; -// $topbar-arrows: true; //Set false to remove the triangle icon from the menu item - -// -// TYPOGRAPHY -// - -// $include-html-type-classes: $include-html-classes; -// $include-open-sans: true; - -// We use these to control header font styles -// $header-font-family: join("Open Sans", $body-font-family); -// $header-font-weight: 300; -// $header-font-style: normal; -// $header-font-color: #222; -// $header-line-height: 1.4; -// $header-top-margin: .2rem; -// $header-bottom-margin: .5rem; -// $header-text-rendering: optimizeLegibility; - -// We use these to control header font sizes -// $h1-font-size: rem-calc(44); -// $h2-font-size: rem-calc(37); -// $h3-font-size: rem-calc(27); -// $h4-font-size: rem-calc(23); -// $h5-font-size: rem-calc(18); -// $h6-font-size: 1rem; - -// These control how subheaders are styled. -// $subheader-line-height: 1.4; -// $subheader-font-color: scale-color($header-font-color, $lightness: 35%); -// $subheader-font-weight: 300; -// $subheader-top-margin: .2rem; -// $subheader-bottom-margin: .5rem; - -// A general styling -// $small-font-size: 60%; -// $small-font-color: scale-color($header-font-color, $lightness: 35%); - -// We use these to style paragraphs -// $paragraph-font-family: inherit; -// $paragraph-font-weight: normal; -// $paragraph-font-size: 1rem; -// $paragraph-line-height: 1.6; -// $paragraph-margin-bottom: rem-calc(20); -// $paragraph-aside-font-size: rem-calc(14); -// $paragraph-aside-line-height: 1.35; -// $paragraph-aside-font-style: italic; -// $paragraph-text-rendering: optimizeLegibility; - -// We use these to style tags -// $code-color: scale-color($alert-color, $lightness: -27%); -// $code-font-family: Consolas, 'Liberation Mono', Courier, monospace; -// $code-font-weight: bold; - -// We use these to style anchors -// $anchor-text-decoration: none; -// $anchor-font-color: $primary-color; -// $anchor-font-color-hover: scale-color($primary-color, $lightness: -14%); - -// We use these to style the
element -// $hr-border-width: 1px; -// $hr-border-style: solid; -// $hr-border-color: #ddd; -// $hr-margin: rem-calc(20); - -// We use these to style lists -// $list-style-position: outside; -// $list-side-margin: 1.1rem; -// $list-ordered-side-margin: 1.4rem; -// $list-side-margin-no-bullet: 0; -// $list-nested-margin: rem-calc(20); -// $definition-list-header-weight: bold; -// $definition-list-header-margin-bottom: .3rem; -// $definition-list-margin-bottom: rem-calc(12); - -// We use these to style blockquotes -// $blockquote-font-color: scale-color($header-font-color, $lightness: 35%); -// $blockquote-padding: rem-calc(9 20 0 19); -// $blockquote-border: 1px solid #ddd; -// $blockquote-cite-font-size: rem-calc(13); -// $blockquote-cite-font-color: scale-color($header-font-color, $lightness: 23%); -// $blockquote-cite-link-color: $blockquote-cite-font-color; - -// Acronym styles -// $acronym-underline: 1px dotted #ddd; - -// We use these to control padding and margin -// $microformat-padding: rem-calc(10 12); -// $microformat-margin: rem-calc(0 0 20 0); - -// We use these to control the border styles -// $microformat-border-width: 1px; -// $microformat-border-style: solid; -// $microformat-border-color: #ddd; - -// We use these to control full name font styles -// $microformat-fullname-font-weight: bold; -// $microformat-fullname-font-size: rem-calc(15); - -// We use this to control the summary font styles -// $microformat-summary-font-weight: bold; - -// We use this to control abbr padding -// $microformat-abbr-padding: rem-calc(0 1); - -// We use this to control abbr font styles -// $microformat-abbr-font-weight: bold; -// $microformat-abbr-font-decoration: none; - -// -// VISIBILITY CLASSES -// - -// $include-html-visibility-classes: $include-html-classes; +@charset 'utf-8'; +@import 'settings'; @import 'foundation'; -@import 'foundation-icons'; -@import 'font-awesome-sprockets'; -@import 'font-awesome'; + +// If you'd like to include motion-ui the foundation-rails gem comes prepackaged with it, uncomment the 3 @imports, if you are not using the gem you need to install the motion-ui sass package. +// +// @import 'motion-ui/motion-ui'; + +// We include everything by default. To slim your CSS, remove components you don't use. + +@include foundation-global-styles; +@include foundation-grid; +@include foundation-typography; +@include foundation-button; +@include foundation-forms; +@include foundation-visibility-classes; +@include foundation-float-classes; +@include foundation-accordion; +@include foundation-accordion-menu; +@include foundation-badge; +@include foundation-breadcrumbs; +@include foundation-button-group; +@include foundation-callout; +@include foundation-close-button; +@include foundation-drilldown-menu; +@include foundation-dropdown; +@include foundation-dropdown-menu; +@include foundation-flex-video; +@include foundation-label; +@include foundation-media-object; +@include foundation-menu; +@include foundation-menu-icon; +@include foundation-off-canvas; +@include foundation-orbit; +@include foundation-pagination; +@include foundation-progress-bar; +@include foundation-slider; +@include foundation-sticky; +@include foundation-reveal; +@include foundation-switch; +@include foundation-table; +@include foundation-tabs; +@include foundation-thumbnail; +@include foundation-title-bar; +@include foundation-tooltip; +@include foundation-top-bar; + +// If you'd like to include motion-ui the foundation-rails gem comes prepackaged with it, uncomment the 3 @imports, if you are not using the gem you need to install the motion-ui sass package. +// +// @include motion-ui-transitions; +// @include motion-ui-animations; diff --git a/app/assets/stylesheets/head.scss b/app/assets/stylesheets/head.scss index 0e177f6..8cba481 100644 --- a/app/assets/stylesheets/head.scss +++ b/app/assets/stylesheets/head.scss @@ -1,8 +1,35 @@ -.middle-text { - text-align: center; - z-index: 999; +.my-topbar { a { color: #F7F7F7; + + &:hover { + color: #999; + } + + &.title { + font-weight: bold; + } + } + + button { + outline: 0; + } +} + +#offCanvas { + min-height: 100%; + a { + color: #F7F7F7; + &:hover { + background-color: #333; + } + } + + label { + padding: 3px 20px; + background-color: #545454; + color: #B9B9B9; + text-transform: uppercase; } } @@ -16,3 +43,4 @@ cursor: default; } } + diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb index 175138c..f79bdbf 100644 --- a/app/controllers/blogs_controller.rb +++ b/app/controllers/blogs_controller.rb @@ -2,8 +2,8 @@ class BlogsController < ApplicationController def index - @newest = Post.desc(:created_at).first - @recent = Post.desc(:created_at).to_a[1..3] + @newest = Post.order(created_at: :desc).first + @recent = Post.order(created_at: :desc).to_a[1..3] respond_to do |format| format.html format.json @@ -27,7 +27,7 @@ class BlogsController < ApplicationController format.json end end - + def edit @post = Post.find( params[:id] ) redirect_to edit_admin_post_path(@post) diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..10a4cba --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/comment.rb b/app/models/comment.rb index 72d353a..1c5d459 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,17 +1,10 @@ -class Comment - include Mongoid::Document - include Mongoid::Timestamps - - field :name, :type => String - field :content, :type => String - field :email, :type=>String - +class Comment < ApplicationRecord belongs_to :post + validates_presence_of :post_id validates :name, presence: true validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, message: I18n.t('comment_attributes.email') } validates :content, presence: true - validates_presence_of :post_id def reply_emails Comment.where(post_id: self.post_id).collect(&:email).uniq - [ self.email ] - Subscribe.unsubscribe_list diff --git a/app/models/label.rb b/app/models/label.rb index 1d8ce48..d30791b 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -1,9 +1,4 @@ -class Label - include Mongoid::Document - include Mongoid::Timestamps - - field :name, :type => String - +class Label < ApplicationRecord has_and_belongs_to_many :posts validates :name, presence: true end diff --git a/app/models/like.rb b/app/models/like.rb index 70150fb..bf00ebb 100644 --- a/app/models/like.rb +++ b/app/models/like.rb @@ -1,6 +1,4 @@ -class Like - include Mongoid::Document - +class Like < ApplicationRecord belongs_to :post validates_presence_of :post_id end diff --git a/app/models/photo.rb b/app/models/photo.rb index aeef2f5..6b00baf 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -1,7 +1,3 @@ -class Photo - include Mongoid::Document - include Mongoid::Timestamps - field :image - +class Photo < ApplicationRecord mount_uploader :image, PhotoUploader end diff --git a/app/models/post.rb b/app/models/post.rb index cf40b01..3ecb973 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1,18 +1,5 @@ -# encoding : utf-8 -# require 'markdown' -class Post - TECH = "技术" - LIFE = "生活" - CREATOR = "创业" - include Mongoid::Document - include Mongoid::Timestamps - include Mongoid::Pagination - field :title, :type => String - field :content, :type => String - field :type, :type=> String - field :visited_count, :type=>Integer, :default=>0 - +class Post < ActiveRecord::Base has_many :comments has_and_belongs_to_many :labels @@ -20,7 +7,6 @@ class Post validates :title, :presence=>true, :uniqueness=> true validates :content, :presence=>true, :length => { :minimum=> 30 } - validates :type, :presence=>true, :inclusion => { :in => [ TECH, LIFE, CREATOR ] } after_create do if ENV['MAIL_SERVER'].present? @@ -38,35 +24,21 @@ class Post md.render(content) end - def type_en - map = { - '技术' => 'Tech', - '生活' => 'Life', - '创业' => 'Creator', - } - - if I18n.locale == :en - map[type] - else - type - end - end - def visited self.visited_count += 1 self.save self.visited_count end - # 显示给首页截断数据 + # truncate content for home page display def sub_content HTML_Truncator.truncate(content_html, 300, length_in_chars: true) end - # 显示给 meta description + # truncate content for meta description display def meta_content html = HTML_Truncator.truncate(content_html, 100, :length_in_chars => true, ellipsis: '') - # 加上 div 以方便 Nokogiri 获取 text() + # Easily get text for Nokogiri html = '
' + html + '
' Nokogiri.parse(html).text() end diff --git a/app/models/subscribe.rb b/app/models/subscribe.rb index 9e6f544..e0ed2a7 100644 --- a/app/models/subscribe.rb +++ b/app/models/subscribe.rb @@ -1,8 +1,4 @@ -class Subscribe - include Mongoid::Document - field :email, type: String - field :enable, type: Mongoid::Boolean, default: true - +class Subscribe < ApplicationRecord validates :email, presence: true, uniqueness: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, message: '地址无效' } def self.subscribe_list diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index e6ae86d..c9232a4 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -8,41 +8,22 @@ html = content_for?(:title) ? yield(:title) + " | #{ENV['SITE_NAME']}" : ENV['SITE_NAME'] = stylesheet_link_tag "application", media: 'all' = favicon_link_tag 'favicon.png', type: 'image/png' - = javascript_include_tag "vendor/modernizr" = javascript_include_tag "application" = csrf_meta_tags body - if content_for?(:main) = yield(:main) - else - .off-canvas-wrap data-offcanvas='' - .inner-wrap - nav.tab-bar - section.left-small - a.left-off-canvas-toggle.menu-icon href="#" - span - h1.title.middle-text - = link_to ENV['SITE_NAME'], root_path - aslide.left-off-canvas-menu - ul.off-canvas-list + .off-canvas-wrapper + .off-canvas-wrapper-inner data-off-canvas-wrapper='' + .off-canvas.position-left id="offCanvas" data-off-canvas='' + ul.vertical.menu.mobile-ofc li label Menu li = link_to root_path do i.fi-home | #{t('head.home')} - li - = link_to '/tech' do - i.fi-social-evernote - | #{t('head.tech')} - li - = link_to '/life' do - i.fi-torsos-male-female - | #{t('head.life')} - li - = link_to '/creator' do - i.fi-lightbulb - | #{t('head.creator')} li label Archive li @@ -54,7 +35,25 @@ html = link_to about_path do i.fi-torso | #{t('head.about')} - section.main-section ng-app="app" + .off-canvas-content data-off-canvas-content='' + .title-bar.hide-for-medium.my-topbar + .title-bar-left + button.menu-icon type='button' data-open='offCanvas' + span.title-bar-title + = link_to ENV['SITE_NAME'], root_path + .top-bar.show-for-medium.my-topbar + .top-bar-left + ul.dropdown.menu data-dropdown-menu='' + li + = link_to ENV['SITE_NAME'], root_path, class: 'title' + .top-bar-right + ul.dropdown.menu data-dropdown-menu='' + li + a href='#' 首页 + li + a href='#' 时间线 + li + a href='#' 关于 - flash.each do |name, msg| - if msg.is_a?(String) div class=("alert-box #{name == :notice ? "success" : "alert"}") data-alert="" @@ -63,6 +62,5 @@ html = render 'common/welcome_new_year' = yield = render "layouts/footer" - a.exit-off-canvas = render 'layouts/google_analytics' diff --git a/config/application.rb b/config/application.rb index 06c3bc4..2b470db 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,18 +1,12 @@ require File.expand_path('../boot', __FILE__) -# Pick the frameworks you want: -require "active_model/railtie" -require "action_controller/railtie" -require "action_mailer/railtie" -require "action_view/railtie" -require "sprockets/railtie" -require "rails/test_unit/railtie" +require 'rails/all' + Bundler.require(:default, Rails.env) module WBlog class Application < Rails::Application - # Configure sensitive parameters which will be filtered from the log file. config.i18n.available_locales = [:en, :'zh-CN'] #I18n.config.enforce_available_locales = true config.i18n.default_locale = (ENV['LOCALE'] || 'zh-CN').to_sym diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..a4e34ca --- /dev/null +++ b/config/database.yml @@ -0,0 +1,20 @@ +development: + adapter: postgresql + host: localhost + encoding: unicode + database: wblog_development + pool: 5 + +test: + adapter: postgresql + host: localhost + encoding: unicode + database: wblog_test + pool: 5 + +production: + adapter: postgresql + host: localhost + encoding: unicode + database: wblog_production + pool: 5 diff --git a/db/migrate/20160420082319_create_posts.rb b/db/migrate/20160420082319_create_posts.rb new file mode 100644 index 0000000..010887c --- /dev/null +++ b/db/migrate/20160420082319_create_posts.rb @@ -0,0 +1,11 @@ +class CreatePosts < ActiveRecord::Migration[5.0] + def change + create_table :posts do |t| + t.string :title + t.text :content + t.integer :visited_count + + t.timestamps + end + end +end diff --git a/db/migrate/20160420082536_create_comments.rb b/db/migrate/20160420082536_create_comments.rb new file mode 100644 index 0000000..28af756 --- /dev/null +++ b/db/migrate/20160420082536_create_comments.rb @@ -0,0 +1,12 @@ +class CreateComments < ActiveRecord::Migration[5.0] + def change + create_table :comments do |t| + t.string :name + t.string :email + t.text :conent + t.integer :post_id + + t.timestamps + end + end +end diff --git a/db/migrate/20160420082629_create_labels.rb b/db/migrate/20160420082629_create_labels.rb new file mode 100644 index 0000000..f8758a7 --- /dev/null +++ b/db/migrate/20160420082629_create_labels.rb @@ -0,0 +1,9 @@ +class CreateLabels < ActiveRecord::Migration[5.0] + def change + create_table :labels do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20160420082734_create_likes.rb b/db/migrate/20160420082734_create_likes.rb new file mode 100644 index 0000000..a5d75a4 --- /dev/null +++ b/db/migrate/20160420082734_create_likes.rb @@ -0,0 +1,9 @@ +class CreateLikes < ActiveRecord::Migration[5.0] + def change + create_table :likes do |t| + t.integer :post_id + + t.timestamps + end + end +end diff --git a/db/migrate/20160420082811_create_photos.rb b/db/migrate/20160420082811_create_photos.rb new file mode 100644 index 0000000..ea2f924 --- /dev/null +++ b/db/migrate/20160420082811_create_photos.rb @@ -0,0 +1,9 @@ +class CreatePhotos < ActiveRecord::Migration[5.0] + def change + create_table :photos do |t| + t.string :image + + t.timestamps + end + end +end diff --git a/db/migrate/20160420082909_create_subscribes.rb b/db/migrate/20160420082909_create_subscribes.rb new file mode 100644 index 0000000..86084a6 --- /dev/null +++ b/db/migrate/20160420082909_create_subscribes.rb @@ -0,0 +1,10 @@ +class CreateSubscribes < ActiveRecord::Migration[5.0] + def change + create_table :subscribes do |t| + t.string :email + t.boolean :enable + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..f62b8a8 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,61 @@ +# 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 that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20160420082909) do + + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "comments", force: :cascade do |t| + t.string "name" + t.string "email" + t.text "conent" + t.integer "post_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "labels", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "likes", force: :cascade do |t| + t.integer "post_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "photos", force: :cascade do |t| + t.string "image" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "posts", force: :cascade do |t| + t.string "title" + t.text "content" + t.integer "visited_count" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "subscribes", force: :cascade do |t| + t.string "email" + t.boolean "enable" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb new file mode 100644 index 0000000..16c4a46 --- /dev/null +++ b/spec/models/comment_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Comment, :type => :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb new file mode 100644 index 0000000..5700daa --- /dev/null +++ b/spec/models/label_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Label, :type => :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/photo_spec.rb b/spec/models/photo_spec.rb new file mode 100644 index 0000000..87fc11a --- /dev/null +++ b/spec/models/photo_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Photo, :type => :model do + pending "add some examples to (or delete) #{__FILE__}" +end From 368467dfad14adc0f85dd43e47281422f647fd65 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Wed, 20 Apr 2016 23:36:51 +0800 Subject: [PATCH 03/14] Some topbar style improve --- app/assets/stylesheets/admin/dashboard.scss | 7 ++++++ app/controllers/admin/sessions_controller.rb | 1 + app/views/common/_welcome_new_year.html.slim | 4 ++-- app/views/layouts/_footer.html.slim | 2 +- app/views/layouts/admin.html.slim | 24 ++++++++++---------- app/views/layouts/application.html.slim | 12 +++++----- config/routes.rb | 8 +++---- 7 files changed, 33 insertions(+), 25 deletions(-) diff --git a/app/assets/stylesheets/admin/dashboard.scss b/app/assets/stylesheets/admin/dashboard.scss index f8b22f9..13e040e 100644 --- a/app/assets/stylesheets/admin/dashboard.scss +++ b/app/assets/stylesheets/admin/dashboard.scss @@ -1,3 +1,10 @@ .dash-title { padding-top: 2rem; } + +#dashboard-topbar { + background-color: $light-gray; + ul { + background-color: $light-gray; + } +} diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb index 4cfdce5..0e10f8c 100644 --- a/app/controllers/admin/sessions_controller.rb +++ b/app/controllers/admin/sessions_controller.rb @@ -5,6 +5,7 @@ class Admin::SessionsController < ApplicationController end def create + #TODO if ENV['ADMIN_USER'].blank? render :json=> { success: false, message: t('admin.session.no_configuration') } elsif ENV['ADMIN_USER'] != params[:username] diff --git a/app/views/common/_welcome_new_year.html.slim b/app/views/common/_welcome_new_year.html.slim index 2e76ad8..0f5c40e 100644 --- a/app/views/common/_welcome_new_year.html.slim +++ b/app/views/common/_welcome_new_year.html.slim @@ -1,5 +1,5 @@ - if (1.days.from_now).strftime('%-m-%-d') =~ /^1-[123]$/ .new-year - .alert-box data-alert='' + .callout.primary data-closable='' | 我的朋友, 祝你元旦快乐 - a href='#' class='close' × + button.close-button type='button' data-close='' × diff --git a/app/views/layouts/_footer.html.slim b/app/views/layouts/_footer.html.slim index 3683295..62fa378 100644 --- a/app/views/layouts/_footer.html.slim +++ b/app/views/layouts/_footer.html.slim @@ -3,7 +3,7 @@ .footer div span.link yafeilee.me - span.time © 2012 - 2015 + span.time © 2012 - 2016 .license | Designed by span diff --git a/app/views/layouts/admin.html.slim b/app/views/layouts/admin.html.slim index 5b8e396..fe2a386 100644 --- a/app/views/layouts/admin.html.slim +++ b/app/views/layouts/admin.html.slim @@ -4,24 +4,24 @@ html meta name="viewport" content="width=device-width, initial-scale=1.0" title Admin Page for #{ENV['SITE_NAME']} = stylesheet_link_tag "application" - = javascript_include_tag "vendor/modernizr" = javascript_include_tag "application" = csrf_meta_tags body - nav.top-bar data-topbar="" - ul.title-area - li.name - h1 + .title-bar data-responsive-toggle="example-menu" data-hide-for="medium" + button class="menu-icon" type="button" data-toggle='' + .title-bar-title Menu + + .top-bar#dashboard-topbar + .top-bar-left + ul.menu + li = link_to "Dashboard For #{ENV['SITE_NAME']}", admin_root_path - li.toggle-topbar.menu-icon - a href="#" Menu - section.top-bar-section - ul.left li = link_to t('admin.new_post'), new_admin_post_path li = link_to t('admin.posts'), admin_posts_path - ul.right + .top-bar-right + ul.menu li = link_to t('admin.back'), root_path - if admin_username @@ -29,9 +29,9 @@ html = link_to admin_username + ' [ ' + t('admin.logout') + ' ]', admin_session_path(1), method: 'DELETE' - flash.each do |name, msg| - if msg.is_a?(String) - div class=("alert-box #{name.to_sym == :notice ? "success" : "alert"}") data-alert="" + div class=("callout #{name.to_sym == :notice ? "success" : "alert"}") data-closable="" = content_tag :div, msg - a.close href="#" × + button.close-button type='button' data-close='' × .admin-main-field ng-app="app" = yield = render "layouts/footer" diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index c9232a4..855a59f 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -17,7 +17,7 @@ html .off-canvas-wrapper .off-canvas-wrapper-inner data-off-canvas-wrapper='' .off-canvas.position-left id="offCanvas" data-off-canvas='' - ul.vertical.menu.mobile-ofc + ul.vertical.menu li label Menu li @@ -49,16 +49,16 @@ html .top-bar-right ul.dropdown.menu data-dropdown-menu='' li - a href='#' 首页 + = link_to t('head.home'), root_path li - a href='#' 时间线 + = link_to t('head.timeline'), archives_path li - a href='#' 关于 + = link_to t('head.about'), about_path - flash.each do |name, msg| - if msg.is_a?(String) - div class=("alert-box #{name == :notice ? "success" : "alert"}") data-alert="" + div class=("callout #{name.to_sym == :notice ? "success" : "alert"}") data-closable="" = content_tag :div, msg - a.close href="#" × + button.close-button type='button' data-close='' × = render 'common/welcome_new_year' = yield = render "layouts/footer" diff --git a/config/routes.rb b/config/routes.rb index cb6b082..1a077f0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,4 @@ WBlog::Application.routes.draw do - root :to => 'blogs#index' resources :blogs, :only=>[:index, :show, :edit] do collection do @@ -24,7 +23,7 @@ WBlog::Application.routes.draw do # photos resources :photos, only: [:create] get '/qrcodes' => 'qrcodes#show' - + namespace :admin do resources :posts do collection do @@ -33,10 +32,11 @@ WBlog::Application.routes.draw do resources :comments end resources :sessions, :only=>[:new, :create, :destroy] - root to: 'dashboard#index' + root 'dashboard#index' end get '/about' => 'home#index' get '/mobile' => 'home#mobile' - get '/:type' => 'archives#index', constraints: { type: /tech|life|creator/ } + + root 'blogs#index' end From 3615504b76d05e7344254c7f89a34338f493c5cf Mon Sep 17 00:00:00 2001 From: yafeilee Date: Thu, 21 Apr 2016 18:07:55 +0800 Subject: [PATCH 04/14] refactor admin post blog feature without angularjs --- .gitignore | 1 + Gemfile | 4 ++ Gemfile.lock | 17 ++++++ app/assets/javascripts/admin/posts.js.coffee | 25 +++++++- .../angularjs/admin_posts.js.coffee | 35 ------------ app/assets/javascripts/qrcode.js.coffee | 4 ++ app/assets/stylesheets/_settings.scss | 6 +- app/assets/stylesheets/admin/posts.scss | 8 ++- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/blogs.scss | 4 ++ app/controllers/admin/posts_controller.rb | 14 +---- app/controllers/admin/sessions_controller.rb | 12 ++-- app/controllers/archives_controller.rb | 57 +------------------ app/controllers/blogs_controller.rb | 5 +- app/helpers/application_helper.rb | 3 + app/views/admin/posts/_form.html.slim | 28 +++++---- app/views/admin/posts/index.html.slim | 3 +- app/views/admin/sessions/new.html.slim | 12 ++-- app/views/archives/index.html.slim | 47 +++++++-------- app/views/blogs/_comment.html.slim | 29 +++++----- app/views/blogs/_post.html.slim | 26 ++++----- app/views/blogs/_post_head.html.slim | 3 - app/views/kaminari/_gap.html.slim | 7 +++ app/views/kaminari/_last_page.html.slim | 10 ++++ app/views/kaminari/_next_page.html.slim | 10 ++++ app/views/kaminari/_page.html.slim | 11 ++++ app/views/kaminari/_paginator.html.slim | 17 ++++++ app/views/kaminari/_prev_page.html.slim | 10 ++++ app/views/layouts/application.html.slim | 2 +- config/initializers/kaminari_config.rb | 10 ++++ config/routes.rb | 2 +- .../20160421035040_create_labels_posts.rb | 8 +++ ...e_column_default_visited_count_to_posts.rb | 5 ++ ...62614_rename_column_content_to_comments.rb | 5 ++ db/schema.rb | 15 +++-- 35 files changed, 245 insertions(+), 211 deletions(-) delete mode 100644 app/assets/javascripts/angularjs/admin_posts.js.coffee create mode 100644 app/assets/javascripts/qrcode.js.coffee create mode 100644 app/views/kaminari/_gap.html.slim create mode 100644 app/views/kaminari/_last_page.html.slim create mode 100644 app/views/kaminari/_next_page.html.slim create mode 100644 app/views/kaminari/_page.html.slim create mode 100644 app/views/kaminari/_paginator.html.slim create mode 100644 app/views/kaminari/_prev_page.html.slim create mode 100644 config/initializers/kaminari_config.rb create mode 100644 db/migrate/20160421035040_create_labels_posts.rb create mode 100644 db/migrate/20160421041323_change_column_default_visited_count_to_posts.rb create mode 100644 db/migrate/20160421062614_rename_column_content_to_comments.rb diff --git a/.gitignore b/.gitignore index f256735..8361ac8 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ /public/assets/* *.old *.bak +.byebug_history diff --git a/Gemfile b/Gemfile index 75aae8c..8f9bdb3 100644 --- a/Gemfile +++ b/Gemfile @@ -12,6 +12,8 @@ gem 'foundation-rails', '~> 6.2.1' gem 'foundation-icons-sass-rails' gem 'font-awesome-sass' gem 'angularjs-rails' +gem 'carrierwave' +gem 'kaminari', git: 'git@github.com:amatsuda/kaminari.git' gem 'jbuilder' gem 'pg' @@ -48,6 +50,8 @@ group :development do gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' + gem 'byebug' + gem 'rack-cors', :require => 'rack/cors' end diff --git a/Gemfile.lock b/Gemfile.lock index 602cdae..52892bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,11 @@ +GIT + remote: git@github.com:amatsuda/kaminari.git + revision: 0e21d52feca1f79a9aca83613cf053eb5273827e + specs: + kaminari (1.0.0.alpha) + actionpack (>= 3.0.0) + activesupport (>= 3.0.0) + GEM remote: https://rubygems.org/ specs: @@ -46,6 +54,7 @@ GEM babel-source (>= 4.0, < 6) execjs (~> 2.0) builder (3.2.2) + byebug (8.2.4) capybara (2.7.0) addressable mime-types (>= 1.16) @@ -53,6 +62,11 @@ GEM rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) + carrierwave (0.11.0) + activemodel (>= 3.2.0) + activesupport (>= 3.2.0) + json (>= 1.7) + mime-types (>= 1.16) chunky_png (1.3.5) codeclimate-test-reporter (0.5.0) simplecov (>= 0.7.1, < 1.0.0) @@ -306,7 +320,9 @@ PLATFORMS DEPENDENCIES angularjs-rails + byebug capybara + carrierwave chunky_png codeclimate-test-reporter coffee-rails (~> 4.1.0) @@ -322,6 +338,7 @@ DEPENDENCIES html_truncator jbuilder jquery-rails + kaminari! listen (~> 3.0.5) mina mina-multistage diff --git a/app/assets/javascripts/admin/posts.js.coffee b/app/assets/javascripts/admin/posts.js.coffee index 81f67cd..9432672 100644 --- a/app/assets/javascripts/admin/posts.js.coffee +++ b/app/assets/javascripts/admin/posts.js.coffee @@ -7,12 +7,32 @@ $(document).ready -> $('a#upload_photo').click -> $('input[type=file]').show().focus().click().hide() false - + + $('#tabs').on 'change.zf.tabs', ()-> + if $('#preview:visible').length > 0 + $('#preview').text('Loading...') + $.ajax + url: '/admin/posts/preview' + type: 'POST' + data: + content: $('#content-input').val() + success: (data)-> + $('#preview').html(data) + + $('a.tag').click (event)-> + event.preventDefault() + new_labels = $(this).text() + if $('#labels').val() == '' + labels = new_labels + else + labels = $('#labels').val() + ", #{new_labels}" + $('#labels').val(labels) + opt = type: 'POST' url: "/photos" success: (data,status,xhr)-> - txtBox = $("#post_content") + txtBox = $("#content-input") caret_pos = txtBox.caret('pos') src_merged = "\n" + data + "\n" source = txtBox.val() @@ -21,6 +41,5 @@ $(document).ready -> txtBox.caret('pos',caret_pos + src_merged.length) txtBox.scope().content = txtBox.val() txtBox.focus() - $('input[type=file]').fileUpload opt diff --git a/app/assets/javascripts/angularjs/admin_posts.js.coffee b/app/assets/javascripts/angularjs/admin_posts.js.coffee deleted file mode 100644 index aa766dc..0000000 --- a/app/assets/javascripts/angularjs/admin_posts.js.coffee +++ /dev/null @@ -1,35 +0,0 @@ -@app.controller 'AdminPostsController', [ '$scope', '$http', '$location', '$timeout', '$cookies', '$sce', ($scope, $http, $location, $timeout, $cookies, $sce)-> - - $scope.body_active = true - - $scope.init = (id)-> - url = '/admin/posts/' + id + '.json' - $http - url: url - method: 'GET' - .success (res)-> - $scope.title = res.title - $scope.type = res.type - $scope.labels = res.labels - $scope.content = res.content - - $scope.changeToBody = -> - $scope.body_active = true - - $scope.changeToPreview = -> - $scope.body_active = false - $scope.previewHTML = 'Loading...' - $http.post '/admin/posts/preview', { content: $scope.content } - .success (res)-> - $scope.previewHTML = res - - $scope.trustAsPreviewHTML = ()-> - $sce.trustAsHtml($scope.previewHTML) - - $scope.addTag = (e)-> - new_labels= $(e.target).text() - if $scope.labels - $scope.labels += ", #{new_labels}" - else - $scope.labels = new_labels -] diff --git a/app/assets/javascripts/qrcode.js.coffee b/app/assets/javascripts/qrcode.js.coffee new file mode 100644 index 0000000..17a7a06 --- /dev/null +++ b/app/assets/javascripts/qrcode.js.coffee @@ -0,0 +1,4 @@ +$(document).ready ()-> + $('#qrcode-link').click (event)-> + event.preventDefault() + $('.social-share').toggle() diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss index bb9e883..30d4f61 100644 --- a/app/assets/stylesheets/_settings.scss +++ b/app/assets/stylesheets/_settings.scss @@ -233,7 +233,7 @@ $breadcrumbs-item-slash: true; // 11. Button // ---------- -$button-padding: 0.85em 1em; +$button-padding: 1rem 2rem 1.0625rem 2rem; $button-margin: 0 0 $global-margin 0; $button-fill: solid; $button-background: $primary-color; @@ -512,12 +512,12 @@ $show-header-for-stacked: false; $tab-margin: 0; $tab-background: $white; $tab-background-active: $light-gray; -$tab-item-font-size: rem-calc(12); +$tab-item-font-size: rem-calc(16); $tab-item-background-hover: $white; $tab-item-padding: 1.25rem 1.5rem; $tab-expand-max: 6; $tab-content-background: $white; -$tab-content-border: $light-gray; +$tab-content-border: none; $tab-content-color: foreground($tab-background, $primary-color); $tab-content-padding: 1rem; diff --git a/app/assets/stylesheets/admin/posts.scss b/app/assets/stylesheets/admin/posts.scss index 2d1b4a7..ee0cf41 100644 --- a/app/assets/stylesheets/admin/posts.scss +++ b/app/assets/stylesheets/admin/posts.scss @@ -7,10 +7,14 @@ margin-bottom: 2rem; } - #post_content { + #content-input { min-height: 20rem; } + .content-field { + padding: 0; + } + .preview { min-height: 20rem; border: 1px solid #DDDDDD; @@ -25,7 +29,7 @@ #upload_photo { float: right; - margin-top: 2rem; + margin-top: 1.875rem; } tr { diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index e420cb5..78f64db 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -1,6 +1,7 @@ @import 'font-awesome-sprockets'; @import 'font-awesome'; @import 'foundation_and_overrides'; +@import 'foundation-icons'; @import 'aboutme_welcome'; @import 'archives'; diff --git a/app/assets/stylesheets/blogs.scss b/app/assets/stylesheets/blogs.scss index 3ab02e9..0b86b25 100644 --- a/app/assets/stylesheets/blogs.scss +++ b/app/assets/stylesheets/blogs.scss @@ -69,6 +69,10 @@ } } +.social-share { + display: none; +} + .qrcode-wrapper { float: right; margin-top: -2rem; diff --git a/app/controllers/admin/posts_controller.rb b/app/controllers/admin/posts_controller.rb index bcc449c..bf7c8a0 100644 --- a/app/controllers/admin/posts_controller.rb +++ b/app/controllers/admin/posts_controller.rb @@ -10,16 +10,6 @@ class Admin::PostsController < ApplicationController @post = Post.find( params[:id] ) end - def show - post = Post.find( params[:id] ) - render :json=> { - title: post.title, - type: post.type, - labels: post.labels_content(true), - content: post.content - } - end - def destroy @post = Post.find( params[:id] ) if @post.destroy @@ -32,7 +22,7 @@ class Admin::PostsController < ApplicationController end def index - @posts = Post.desc(:created_at) + @posts = Post.order(created_at: :desc).page(params[:page]).per(1) end def create @@ -71,7 +61,7 @@ class Admin::PostsController < ApplicationController private def initialize_or_create_labels(labels) @post.labels = [] - labels.split(",").each do |name| + labels.split(",").map { |i| i.strip }.uniq.each do |name| label = Label.find_or_initialize_by(name: name.strip) label.save! @post.labels << label diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb index 0e10f8c..d661c29 100644 --- a/app/controllers/admin/sessions_controller.rb +++ b/app/controllers/admin/sessions_controller.rb @@ -5,17 +5,19 @@ class Admin::SessionsController < ApplicationController end def create - #TODO if ENV['ADMIN_USER'].blank? - render :json=> { success: false, message: t('admin.session.no_configuration') } + flash.now[:alert] = t('admin.session.no_configuration') + render :new elsif ENV['ADMIN_USER'] != params[:username] - render :json=> { success: false, message: t('admin.session.username_error') } + flash.now[:alert] = t('admin.session.username_error') + render :new elsif ENV['ADMIN_PASSWORD'] != params[:password] - render :json=> { success: false, message: t('admin.session.password_error') } + flash.now[:alert] = t('admin.session.password_error') + render :new else flash[:notice] = t('admin.session.login_success') session[:login] = true - render :json=> { success: true } + redirect_to admin_root_path end end diff --git a/app/controllers/archives_controller.rb b/app/controllers/archives_controller.rb index 7d31986..c89c371 100644 --- a/app/controllers/archives_controller.rb +++ b/app/controllers/archives_controller.rb @@ -1,60 +1,5 @@ class ArchivesController < ApplicationController def index - type = map[params[:type]] - limit = 10 - start_with = params[:start_with] - @posts = Post.desc(:created_at) - - if type - @posts = @posts.where(type: type) - @type = type - end - - # all 与 start_with 参数同在, 说明是要获取所有start_with之前的数据 - if params[:all] and params[:start_with] - @posts = @posts.where(:created_at.gte => Time.at(start_with.to_i)) - else - @posts = @posts.limit(limit) - end - - if !params[:all] and start_with - @posts = @posts.where(:created_at.lt => Time.at(start_with.to_i)) - end - - #update start_with - unless @posts.empty? - start_with = @posts[-1].created_at.to_i.to_s - end - - respond_to do |format| - format.json do - render :json => { - posts: @posts.collect { |post| build_summary(post) }, - start_with: start_with - } - end - format.html - end - end - - private - def map - { - "life"=> "生活", - "tech"=> "技术", - "creator"=> "创业" - } - end - - def build_summary(post) - { - title: post.title, - type: post.type_en, - created_at: format_date(post.created_at), - id: post.id.to_s, - liked_count: post.liked_count, - visited_count: post.visited_count, - labels: post.labels_content - } + @posts = Post.order(created_at: :desc) end end diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb index f79bdbf..67db492 100644 --- a/app/controllers/blogs_controller.rb +++ b/app/controllers/blogs_controller.rb @@ -19,9 +19,10 @@ class BlogsController < ApplicationController def show @post = Post.find(params[:id]) @post.visited - @prev = Post.where(:created_at.lt => @post.created_at).desc(:created_at).where(:id.ne => @post.id).first - @next = Post.where(:created_at.gt => @post.created_at).asc(:created_at).where(:id.ne => @post.id).first + @prev = Post.where('created_at < ?', @post.created_at).order(created_at: :desc).first + @prev = Post.where('created_at > ?', @post.created_at).order(created_at: :asc).first @comments = @post.comments + @likes_count = @post.likes.count respond_to do |format| format.html format.json diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index de6be79..ae257cc 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,2 +1,5 @@ module ApplicationHelper + def format_date(time) + time.strftime('%Y-%m-%d') + end end diff --git a/app/views/admin/posts/_form.html.slim b/app/views/admin/posts/_form.html.slim index f730699..a5572e5 100644 --- a/app/views/admin/posts/_form.html.slim +++ b/app/views/admin/posts/_form.html.slim @@ -2,14 +2,11 @@ = simple_form_for(@post, url: url, html: {novalidate: '' }) do |f| .row .large-6.columns - = f.input :title, label: t('admin.posts_attributes.title'), "ng-model"=>"title", input_html: { name: 'title' } - .row - .small-6.large-3.columns - = f.input :type, :as=>:select, :collection=> [ Post::TECH, Post::LIFE, Post::CREATOR ], label: t('admin.posts_attributes.type'), "ng-model"=>"type", input_html: { name: 'type' } + = f.input :title, label: t('admin.posts_attributes.title'), input_html: { name: 'title' } .row .small-12.large-6.columns = label_tag :labels, t('admin.posts_attributes.labels') - = text_field_tag :labels, @post.labels_content(true), "ng-model"=>"labels", "ng-initial" => '' + = text_field_tag :labels, @post.labels_content(true) .row .small-12.columns @@ -17,22 +14,23 @@ | #{t('admin.posts_attributes.already_labels')} span - Label.all.each do |label| - a.tag href="#" ng-click="addTag($event)" #{label.name} + a.tag href="#" #{label.name} / tabs and upload file field - dl.tabs - dd ng-class="{ active: body_active }" - a href="" ng-click="changeToBody()" #{t('admin.posts_attributes.content')} - dd ng-class="{ active: !body_active }" - a href="#" ng-click="changeToPreview()" #{t('admin.posts_attributes.preview')} + ul.tabs#tabs data-tabs='' + li.tabs-title.is-active + a href="#content" #{t('admin.posts_attributes.content')} + li.tabs-title + a href="#preview" #{t('admin.posts_attributes.preview')} = link_to t('admin.posts_attributes.upload_photo'), "#", :id=>'upload_photo' input[type="file" style="display: none;"] - .content-field ng-show="body_active" ng-model= 'content' - = f.input :content, :as=> :text, :label => false, input_html: { name: 'content', "ng-model"=>'content', 'ng-initial'=>'' } + .tabs-content data-tabs-content='tabs' + .tabs-panel.content-field.is-active#content + = f.input :content, :as=> :text, :label => false, input_html: { name: 'content', id: 'content-input' } - .preview.markdown ng-hide="body_active" ng-bind-html=" trustAsPreviewHTML() " + .tabs-panel.preview.markdown#preview .row .small-12.large-6.columns.posts-button - button #{t('admin.posts_attributes.submit')} + button.button type='submit' #{t('admin.posts_attributes.submit')} diff --git a/app/views/admin/posts/index.html.slim b/app/views/admin/posts/index.html.slim index 2055577..253f589 100644 --- a/app/views/admin/posts/index.html.slim +++ b/app/views/admin/posts/index.html.slim @@ -15,8 +15,6 @@ td.admin-post-summary-field i.fi-calendar span #{format_time(post.created_at)} - i.fi-list - span #{ post.type_en } i.fi-pricetag-multiple span #{ post.labels_content } i.fi-torsos @@ -27,3 +25,4 @@ = link_to t('comment'), admin_post_comments_path(post.id), class: 'edit-post-link' = link_to t('edit'), edit_admin_post_path(post), class: 'edit-post-link' = link_to t('destroy'), admin_post_path(post), method: 'DELETE', 'data-confirm' => '确认删除?' + == paginate @posts diff --git a/app/views/admin/sessions/new.html.slim b/app/views/admin/sessions/new.html.slim index 44f98a6..242d5d9 100644 --- a/app/views/admin/sessions/new.html.slim +++ b/app/views/admin/sessions/new.html.slim @@ -1,16 +1,12 @@ .row ng-controller="AdminSessionsController" .small-12.large-8.columns h3.blog-title #{t('admin.session.title')} - form ng-submit="login()" + = form_tag admin_sessions_path .row .small-12.large-8.columns = label_tag 'username', t('admin.session.username') - = text_field_tag 'username', nil, placeholder: t('admin.session.username_placeholder'), "ng-model"=>"username" + = text_field_tag 'username', params[:username], placeholder: t('admin.session.username_placeholder') = label_tag 'username', t('admin.session.password') - = password_field_tag 'password', nil, placeholder: t('admin.session.password_placeholder'), "ng-model"=>"password" + = password_field_tag 'password', params[:password], placeholder: t('admin.session.password_placeholder') - p - .alert-box.warning ng-show=" error_msg " - |{{ error_msg }} - - button #{t('admin.session.login_button')} + button.button type='submit' #{t('admin.session.login_button')} diff --git a/app/views/archives/index.html.slim b/app/views/archives/index.html.slim index e929fc8..a5ba485 100644 --- a/app/views/archives/index.html.slim +++ b/app/views/archives/index.html.slim @@ -1,30 +1,21 @@ - content_for(:title) do - | #{@type ? @type : t('title.timeline')} -.row ng-controller="ArchivesController" ng-cloak="" + | #{t('title.timeline')} +.row .small-12.large-9.large-centered.columns - ul.archives-field ng-model="type" ng-init=" type= '#{@type}' " - li ng-repeat=" post in posts " - a.blog-title ng-href="{{ visit(post.id) }}" - |{{ post.title }} - p.tags-field - i.fi-calendar - span - |{{ post.created_at }} - i.fi-list-thumbnails - span - |{{ post.type }} - i.fi-pricetag-multiple - span - |{{ post.labels }} - i.fi-torsos - span - |{{ post.visited_count }} - i.fi-heart - span - |{{ post.liked_count }} - .no-more-field - p ng-show="no_more_flag" #{t('nocontent')} - - .load-more - button.small ng-click="load()" ng-show="!loading_flag" Load More - button.small ng-show="loading_flag" Loading + ul.archives-field + - @posts.each do |post| + li + = link_to post.title, blog_path(post), class: 'blog-title' + p.tags-field + i.fi-calendar + span + = format_date(post.created_at) + i.fi-pricetag-multiple + span + = post.labels_content + i.fi-torsos + span + = post.visited_count + i.fi-heart + span + = post.liked_count diff --git a/app/views/blogs/_comment.html.slim b/app/views/blogs/_comment.html.slim index c3b87b8..74b0e69 100644 --- a/app/views/blogs/_comment.html.slim +++ b/app/views/blogs/_comment.html.slim @@ -1,21 +1,22 @@ -.row ng-controller="CommentsController" ng-cloak="" +.row .small-12.large-9.large-centered.columns form novalidate='' name='form' + = form_for Comment.new, url: blog_comments_path(@post) do |f| .row .small-12.large-12.columns - = text_area_tag(:content, nil, placeholder: t('comment_placeholder.content'), 'ng-model'=> 'content', 'ng-required'=> true) + = f.text_area :content, placeholder: t('comment_placeholder.content') .row .small-12.large-6.columns - = text_field_tag(:name, nil, placeholder: t('comment_placeholder.name'), 'ng-model'=> 'name', 'ng-required'=> 'true') - = text_field_tag(:email, nil, placeholder: t('comment_placeholder.email'), 'ng-model'=> 'email', 'ng-pattern'=>"/^.+@.+$/", 'ng-required'=>"true") - button.comment-submit ng-click="submit()" ng-disabled="form.$invalid || submitting" {{ submitting && "#{t('comment_placeholder.submitting')}" || "#{t('comment_placeholder.submit')}" }} - p.comment-success ng-show="publish_success" #{t('comment_placeholder.publish_success')} - p.comment-fail ng-show="publish_success == false" #{t('comment_placeholder.publish_fail')}: {{ publish_fail_msg }} + = f.text_field :name, placeholder: t('comment_placeholder.name') + = f.text_field :email, placeholder: t('comment_placeholder.email') + button.button.comment-submit type='submit' #{t('comment_placeholder.submit')} .comment-diag - .comment-wrapper ng-repeat=" comment in comments " - p.name - |{{ comment.name + " • " }} - span.created-at - |{{ comment.created_at }} - / ignore "white-space: pre" 's effect -

{{ comment.content }}

+ .comment-wrapper + - comments.each do |comment| + p.name + | #{comment.name} + | " • " + span.created-at + | #{comment.created_at } + / ignore "white-space: pre" 's effect +

#{comment.content}

diff --git a/app/views/blogs/_post.html.slim b/app/views/blogs/_post.html.slim index 03601e1..ab1635d 100644 --- a/app/views/blogs/_post.html.slim +++ b/app/views/blogs/_post.html.slim @@ -8,21 +8,15 @@ p.ptag.published-at span #{format_date(post.created_at)} = render 'common/copyright' - hr.blog-over -p ng-controller="LikesController" ng-cloak="" - button.like-button ng-show="! is_liked " ng-click="submit()" - |{{ count }} - span Like - button.like-button.liked ng-show=" is_liked " ng-click="cancel()" - |{{ count }} - span Like - div ng-controller = "QRCodesController" - .qrcode - a href="#" ng-model="qrcode" ng-init="qrcode=false" ng-click="show()" - i.fi-link - | #{t('qr_code')} +p + button.button.like-button type='button' + | #{@likes_count} Like + .qrcode + a#qrcode-link href="#" + i.fi-link + | #{t('qr_code')} - .social-share ng-show='qrcode' - .qrcode-wrapper - = render partial: "qrcode", locals: { str: blog_url(post) } + .social-share + .qrcode-wrapper + = render partial: "qrcode", locals: { str: blog_url(post) } diff --git a/app/views/blogs/_post_head.html.slim b/app/views/blogs/_post_head.html.slim index 0caf431..ab5e3c7 100644 --- a/app/views/blogs/_post_head.html.slim +++ b/app/views/blogs/_post_head.html.slim @@ -1,9 +1,6 @@ / require: locals: { post : post } h2.blog-title #{post.title} p.ptag - span - i.fi-list-thumbnails - span #{post.type_en} span i.fi-pricetag-multiple span #{post.labels_content} diff --git a/app/views/kaminari/_gap.html.slim b/app/views/kaminari/_gap.html.slim new file mode 100644 index 0000000..05cb8f4 --- /dev/null +++ b/app/views/kaminari/_gap.html.slim @@ -0,0 +1,7 @@ +/ Non-link tag that stands for skipped pages... + - available local variables + current_page : a page object for the currently displayed page + total_pages : total number of pages + per_page : number of items to fetch per page + remote : data-remote +li.ellipsis diff --git a/app/views/kaminari/_last_page.html.slim b/app/views/kaminari/_last_page.html.slim new file mode 100644 index 0000000..cc0a22b --- /dev/null +++ b/app/views/kaminari/_last_page.html.slim @@ -0,0 +1,10 @@ +/ Link to the "Last" page + - available local variables + url : url to the last page + current_page : a page object for the currently displayed page + total_pages : total number of pages + per_page : number of items to fetch per page + remote : data-remote +span.last + == link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, :remote => remote +' diff --git a/app/views/kaminari/_next_page.html.slim b/app/views/kaminari/_next_page.html.slim new file mode 100644 index 0000000..b378eb4 --- /dev/null +++ b/app/views/kaminari/_next_page.html.slim @@ -0,0 +1,10 @@ +/ Link to the "Next" page + - available local variables + url : url to the next page + current_page : a page object for the currently displayed page + total_pages : total number of pages + per_page : number of items to fetch per page + remote : data-remote +li.pagination-next class="#{'disabled' if current_page.last?}" + == link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, :rel => 'next', :remote => remote +' diff --git a/app/views/kaminari/_page.html.slim b/app/views/kaminari/_page.html.slim new file mode 100644 index 0000000..0731808 --- /dev/null +++ b/app/views/kaminari/_page.html.slim @@ -0,0 +1,11 @@ +/ Link showing page number + - available local variables + page : a page object for "this" page + url : url to this page + current_page : a page object for the currently displayed page + total_pages : total number of pages + per_page : number of items to fetch per page + remote : data-remote +li class="page#{' current' if page.current?}" + == link_to_unless page.current?, page, url, {:remote => remote, :rel => page.rel} +' diff --git a/app/views/kaminari/_paginator.html.slim b/app/views/kaminari/_paginator.html.slim new file mode 100644 index 0000000..e7ff760 --- /dev/null +++ b/app/views/kaminari/_paginator.html.slim @@ -0,0 +1,17 @@ +/ The container tag + - available local variables + current_page : a page object for the currently displayed page + total_pages : total number of pages + per_page : number of items to fetch per page + remote : data-remote + paginator : the paginator that renders the pagination tags inside + +== paginator.render do + ul.pagination + == prev_page_tag + - each_page do |page| + - if page.left_outer? || page.right_outer? || page.inside_window? + == page_tag page + - elsif !page.was_truncated? + == gap_tag + == next_page_tag diff --git a/app/views/kaminari/_prev_page.html.slim b/app/views/kaminari/_prev_page.html.slim new file mode 100644 index 0000000..0d563c6 --- /dev/null +++ b/app/views/kaminari/_prev_page.html.slim @@ -0,0 +1,10 @@ +/ Link to the "Previous" page + - available local variables + url : url to the previous page + current_page : a page object for the currently displayed page + total_pages : total number of pages + per_page : number of items to fetch per page + remote : data-remote +li.pagination-previous class="#{'disabled' if current_page.first?}" + == link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, :rel => 'prev', :remote => remote +' diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 855a59f..0d2c457 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -10,7 +10,7 @@ html = favicon_link_tag 'favicon.png', type: 'image/png' = javascript_include_tag "application" = csrf_meta_tags - body + body data-whatinput="mouse" - if content_for?(:main) = yield(:main) - else diff --git a/config/initializers/kaminari_config.rb b/config/initializers/kaminari_config.rb new file mode 100644 index 0000000..ed1fe79 --- /dev/null +++ b/config/initializers/kaminari_config.rb @@ -0,0 +1,10 @@ +Kaminari.configure do |config| + config.default_per_page = 10 + # config.max_per_page = nil + # config.window = 4 + # config.outer_window = 0 + # config.left = 0 + # config.right = 0 + # config.page_method_name = :page + # config.param_name = :page +end diff --git a/config/routes.rb b/config/routes.rb index 1a077f0..a4632f1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,7 +25,7 @@ WBlog::Application.routes.draw do get '/qrcodes' => 'qrcodes#show' namespace :admin do - resources :posts do + resources :posts, except: [:show] do collection do post :preview end diff --git a/db/migrate/20160421035040_create_labels_posts.rb b/db/migrate/20160421035040_create_labels_posts.rb new file mode 100644 index 0000000..8bc0cf5 --- /dev/null +++ b/db/migrate/20160421035040_create_labels_posts.rb @@ -0,0 +1,8 @@ +class CreateLabelsPosts < ActiveRecord::Migration[5.0] + def change + create_table :labels_posts, id: false do |t| + t.integer :label_id + t.integer :post_id + end + end +end diff --git a/db/migrate/20160421041323_change_column_default_visited_count_to_posts.rb b/db/migrate/20160421041323_change_column_default_visited_count_to_posts.rb new file mode 100644 index 0000000..7e3c47c --- /dev/null +++ b/db/migrate/20160421041323_change_column_default_visited_count_to_posts.rb @@ -0,0 +1,5 @@ +class ChangeColumnDefaultVisitedCountToPosts < ActiveRecord::Migration[5.0] + def change + change_column_default :posts, :visited_count, 0 + end +end diff --git a/db/migrate/20160421062614_rename_column_content_to_comments.rb b/db/migrate/20160421062614_rename_column_content_to_comments.rb new file mode 100644 index 0000000..4be97df --- /dev/null +++ b/db/migrate/20160421062614_rename_column_content_to_comments.rb @@ -0,0 +1,5 @@ +class RenameColumnContentToComments < ActiveRecord::Migration[5.0] + def change + rename_column :comments, :conent, :content + end +end diff --git a/db/schema.rb b/db/schema.rb index f62b8a8..32b8b4a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160420082909) do +ActiveRecord::Schema.define(version: 20160421062614) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -19,7 +19,7 @@ ActiveRecord::Schema.define(version: 20160420082909) do create_table "comments", force: :cascade do |t| t.string "name" t.string "email" - t.text "conent" + t.text "content" t.integer "post_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -31,6 +31,11 @@ ActiveRecord::Schema.define(version: 20160420082909) do t.datetime "updated_at", null: false end + create_table "labels_posts", id: false, force: :cascade do |t| + t.integer "label_id" + t.integer "post_id" + end + create_table "likes", force: :cascade do |t| t.integer "post_id" t.datetime "created_at", null: false @@ -46,9 +51,9 @@ ActiveRecord::Schema.define(version: 20160420082909) do create_table "posts", force: :cascade do |t| t.string "title" t.text "content" - t.integer "visited_count" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "visited_count", default: 0 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "subscribes", force: :cascade do |t| From 02f09f1d38b6b7f6c9b8d90f9fd294817f6e6546 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Thu, 21 Apr 2016 18:12:30 +0800 Subject: [PATCH 05/14] Adjust paginator window argument --- app/controllers/admin/posts_controller.rb | 2 +- config/initializers/kaminari_config.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/posts_controller.rb b/app/controllers/admin/posts_controller.rb index bf7c8a0..d583c48 100644 --- a/app/controllers/admin/posts_controller.rb +++ b/app/controllers/admin/posts_controller.rb @@ -22,7 +22,7 @@ class Admin::PostsController < ApplicationController end def index - @posts = Post.order(created_at: :desc).page(params[:page]).per(1) + @posts = Post.order(created_at: :desc).page(params[:page]) end def create diff --git a/config/initializers/kaminari_config.rb b/config/initializers/kaminari_config.rb index ed1fe79..0f238a6 100644 --- a/config/initializers/kaminari_config.rb +++ b/config/initializers/kaminari_config.rb @@ -1,10 +1,10 @@ Kaminari.configure do |config| config.default_per_page = 10 # config.max_per_page = nil - # config.window = 4 + config.window = 2 # config.outer_window = 0 - # config.left = 0 - # config.right = 0 + config.left = 0 + config.right = 0 # config.page_method_name = :page # config.param_name = :page end From 27314da99a51d1304140169227053caa3448c942 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Thu, 21 Apr 2016 21:01:52 +0800 Subject: [PATCH 06/14] Add turbolinks, remove useless angularjs code --- Gemfile | 4 +- Gemfile.lock | 12 +- app/assets/javascripts/admin/posts.js.coffee | 2 +- app/assets/javascripts/angular-scroll.js | 589 ------------------ app/assets/javascripts/angularjs.js.coffee | 15 - .../javascripts/angularjs/about.js.coffee | 36 -- .../angularjs/about_scroll.js.coffee | 14 - .../angularjs/admin_sessions.js.coffee | 21 - .../javascripts/angularjs/archives.js.coffee | 43 -- .../javascripts/angularjs/comments.js.coffee | 35 -- .../angularjs/directives.js.coffee | 9 - .../javascripts/angularjs/likes.js.coffee | 38 -- .../javascripts/angularjs/qrcodes.js.coffee | 4 - .../angularjs/subscribes.js.coffee | 10 - app/assets/javascripts/application.js | 7 +- app/assets/javascripts/qrcode.js.coffee | 2 +- app/assets/stylesheets/angularjs.scss | 3 - app/assets/stylesheets/application.scss | 7 +- app/controllers/archives_controller.rb | 2 +- app/views/archives/index.html.slim | 1 + app/views/layouts/application.html.slim | 4 +- config/database.yml.example | 20 + config/mongoid.yml.example | 29 - config/puma.rb | 8 + 24 files changed, 52 insertions(+), 863 deletions(-) delete mode 100644 app/assets/javascripts/angular-scroll.js delete mode 100644 app/assets/javascripts/angularjs.js.coffee delete mode 100644 app/assets/javascripts/angularjs/about.js.coffee delete mode 100644 app/assets/javascripts/angularjs/about_scroll.js.coffee delete mode 100644 app/assets/javascripts/angularjs/admin_sessions.js.coffee delete mode 100644 app/assets/javascripts/angularjs/archives.js.coffee delete mode 100644 app/assets/javascripts/angularjs/comments.js.coffee delete mode 100644 app/assets/javascripts/angularjs/directives.js.coffee delete mode 100644 app/assets/javascripts/angularjs/likes.js.coffee delete mode 100644 app/assets/javascripts/angularjs/qrcodes.js.coffee delete mode 100644 app/assets/javascripts/angularjs/subscribes.js.coffee delete mode 100644 app/assets/stylesheets/angularjs.scss create mode 100644 config/database.yml.example delete mode 100644 config/mongoid.yml.example create mode 100644 config/puma.rb diff --git a/Gemfile b/Gemfile index 8f9bdb3..45e1fcb 100644 --- a/Gemfile +++ b/Gemfile @@ -11,9 +11,9 @@ gem 'jquery-rails' gem 'foundation-rails', '~> 6.2.1' gem 'foundation-icons-sass-rails' gem 'font-awesome-sass' -gem 'angularjs-rails' gem 'carrierwave' gem 'kaminari', git: 'git@github.com:amatsuda/kaminari.git' +gem 'turbolinks', '~> 5.x' gem 'jbuilder' gem 'pg' @@ -33,7 +33,7 @@ gem 'redis-namespace' gem 'rest-client' gem 'newrelic_rpm' -gem 'unicorn' +gem 'puma' gem 'mina', require: false gem 'mina-multistage', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 52892bb..d5255e9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -136,7 +136,6 @@ GEM railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (1.8.3) - kgio (2.10.0) listen (3.0.6) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9.7) @@ -178,6 +177,7 @@ GEM pry (>= 0.9.10, < 0.11.0) pry-rails (0.3.4) pry (>= 0.9.10) + puma (3.4.0) quiet_assets (1.1.0) railties (>= 3.1, < 5.0) rack (2.0.0.alpha) @@ -211,7 +211,6 @@ GEM method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - raindrops (0.16.0) rake (11.1.2) rb-fsevent (0.9.7) rb-inotify (0.9.7) @@ -299,6 +298,9 @@ GEM thor (0.19.1) thread_safe (0.3.5) tilt (2.0.2) + turbolinks (5.0.0.beta2) + turbolinks-source + turbolinks-source (5.0.0.beta4) tzinfo (1.2.2) thread_safe (~> 0.1) uglifier (3.0.0) @@ -306,9 +308,6 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.2) - unicorn (5.1.0) - kgio (~> 2.6) - raindrops (~> 0.7) websocket-driver (0.6.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -350,6 +349,7 @@ DEPENDENCIES pg pry-nav pry-rails + puma quiet_assets rack-cors rails (>= 5.0.0.beta3, < 5.1) @@ -366,8 +366,8 @@ DEPENDENCIES slim-rails spring spring-watcher-listen (~> 2.0.0) + turbolinks (~> 5.x) uglifier (>= 2.7.2) - unicorn BUNDLED WITH 1.11.2 diff --git a/app/assets/javascripts/admin/posts.js.coffee b/app/assets/javascripts/admin/posts.js.coffee index 9432672..9aa384f 100644 --- a/app/assets/javascripts/admin/posts.js.coffee +++ b/app/assets/javascripts/admin/posts.js.coffee @@ -3,7 +3,7 @@ # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ # -$(document).ready -> +$(document).on 'turbolinks:load', -> $('a#upload_photo').click -> $('input[type=file]').show().focus().click().hide() false diff --git a/app/assets/javascripts/angular-scroll.js b/app/assets/javascripts/angular-scroll.js deleted file mode 100644 index 9d22e9b..0000000 --- a/app/assets/javascripts/angular-scroll.js +++ /dev/null @@ -1,589 +0,0 @@ -/** - * x is a value between 0 and 1, indicating where in the animation you are. - */ -var duScrollDefaultEasing = function (x) { - 'use strict'; - - if(x < 0.5) { - return Math.pow(x*2, 2)/2; - } - return 1-Math.pow((1-x)*2, 2)/2; -}; - -angular.module('duScroll', [ - 'duScroll.scrollspy', - 'duScroll.smoothScroll', - 'duScroll.scrollContainer', - 'duScroll.spyContext', - 'duScroll.scrollHelpers' -]) - //Default animation duration for smoothScroll directive - .value('duScrollDuration', 350) - //Scrollspy debounce interval, set to 0 to disable - .value('duScrollSpyWait', 100) - //Wether or not multiple scrollspies can be active at once - .value('duScrollGreedy', false) - //Default offset for smoothScroll directive - .value('duScrollOffset', 0) - //Default easing function for scroll animation - .value('duScrollEasing', duScrollDefaultEasing); - - -angular.module('duScroll.scrollHelpers', ['duScroll.requestAnimation']) -.run(["$window", "$q", "cancelAnimation", "requestAnimation", "duScrollEasing", "duScrollDuration", "duScrollOffset", function($window, $q, cancelAnimation, requestAnimation, duScrollEasing, duScrollDuration, duScrollOffset) { - 'use strict'; - - var proto = angular.element.prototype; - - var isDocument = function(el) { - return (typeof HTMLDocument !== 'undefined' && el instanceof HTMLDocument) || (el.nodeType && el.nodeType === el.DOCUMENT_NODE); - }; - - var isElement = function(el) { - return (typeof HTMLElement !== 'undefined' && el instanceof HTMLElement) || (el.nodeType && el.nodeType === el.ELEMENT_NODE); - }; - - var unwrap = function(el) { - return isElement(el) || isDocument(el) ? el : el[0]; - }; - - proto.scrollTo = function(left, top, duration, easing) { - var aliasFn; - if(angular.isElement(left)) { - aliasFn = this.scrollToElement; - } else if(duration) { - aliasFn = this.scrollToAnimated; - } - if(aliasFn) { - return aliasFn.apply(this, arguments); - } - var el = unwrap(this); - if(isDocument(el)) { - return $window.scrollTo(left, top); - } - el.scrollLeft = left; - el.scrollTop = top; - }; - - var scrollAnimation, deferred; - proto.scrollToAnimated = function(left, top, duration, easing) { - if(duration && !easing) { - easing = duScrollEasing; - } - var startLeft = this.scrollLeft(), - startTop = this.scrollTop(), - deltaLeft = Math.round(left - startLeft), - deltaTop = Math.round(top - startTop); - - var startTime = null; - var el = this; - - var cancelOnEvents = 'scroll mousedown mousewheel touchmove keydown'; - var cancelScrollAnimation = function($event) { - if (!$event || $event.which > 0) { - el.unbind(cancelOnEvents, cancelScrollAnimation); - cancelAnimation(scrollAnimation); - deferred.reject(); - scrollAnimation = null; - } - }; - - if(scrollAnimation) { - cancelScrollAnimation(); - } - deferred = $q.defer(); - - if(!deltaLeft && !deltaTop) { - deferred.resolve(); - return deferred.promise; - } - - var animationStep = function(timestamp) { - if (startTime === null) { - startTime = timestamp; - } - - var progress = timestamp - startTime; - var percent = (progress >= duration ? 1 : easing(progress/duration)); - - el.scrollTo( - startLeft + Math.ceil(deltaLeft * percent), - startTop + Math.ceil(deltaTop * percent) - ); - if(percent < 1) { - scrollAnimation = requestAnimation(animationStep); - } else { - el.unbind(cancelOnEvents, cancelScrollAnimation); - scrollAnimation = null; - deferred.resolve(); - } - }; - - //Fix random mobile safari bug when scrolling to top by hitting status bar - el.scrollTo(startLeft, startTop); - - el.bind(cancelOnEvents, cancelScrollAnimation); - - scrollAnimation = requestAnimation(animationStep); - return deferred.promise; - }; - - proto.scrollToElement = function(target, offset, duration, easing) { - var el = unwrap(this); - if(!angular.isNumber(offset) || isNaN(offset)) { - offset = duScrollOffset; - } - var top = this.scrollTop() + unwrap(target).getBoundingClientRect().top - offset; - if(isElement(el)) { - top -= el.getBoundingClientRect().top; - } - return this.scrollTo(0, top, duration, easing); - }; - - var overloaders = { - scrollLeft: function(value, duration, easing) { - if(angular.isNumber(value)) { - return this.scrollTo(value, this.scrollTop(), duration, easing); - } - var el = unwrap(this); - if(isDocument(el)) { - return $window.scrollX || document.documentElement.scrollLeft || document.body.scrollLeft; - } - return el.scrollLeft; - }, - scrollTop: function(value, duration, easing) { - if(angular.isNumber(value)) { - return this.scrollTo(this.scrollTop(), value, duration, easing); - } - var el = unwrap(this); - if(isDocument(el)) { - return $window.scrollY || document.documentElement.scrollTop || document.body.scrollTop; - } - return el.scrollTop; - } - }; - - proto.scrollToElementAnimated = function(target, offset, duration, easing) { - return this.scrollToElement(target, offset, duration || duScrollDuration, easing); - }; - - proto.scrollTopAnimated = function(top, duration, easing) { - return this.scrollTop(top, duration || duScrollDuration, easing); - }; - - proto.scrollLeftAnimated = function(left, duration, easing) { - return this.scrollLeft(left, duration || duScrollDuration, easing); - }; - - //Add duration and easing functionality to existing jQuery getter/setters - var overloadScrollPos = function(superFn, overloadFn) { - return function(value, duration, easing) { - if(duration) { - return overloadFn.apply(this, arguments); - } - return superFn.apply(this, arguments); - }; - }; - - for(var methodName in overloaders) { - proto[methodName] = (proto[methodName] ? overloadScrollPos(proto[methodName], overloaders[methodName]) : overloaders[methodName]); - } -}]); - - -//Adapted from https://gist.github.com/paulirish/1579671 -angular.module('duScroll.polyfill', []) -.factory('polyfill', ["$window", function($window) { - 'use strict'; - - var vendors = ['webkit', 'moz', 'o', 'ms']; - - return function(fnName, fallback) { - if($window[fnName]) { - return $window[fnName]; - } - var suffix = fnName.substr(0, 1).toUpperCase() + fnName.substr(1); - for(var key, i = 0; i < vendors.length; i++) { - key = vendors[i]+suffix; - if($window[key]) { - return $window[key]; - } - } - return fallback; - }; -}]); - -angular.module('duScroll.requestAnimation', ['duScroll.polyfill']) -.factory('requestAnimation', ["polyfill", "$timeout", function(polyfill, $timeout) { - 'use strict'; - - var lastTime = 0; - var fallback = function(callback, element) { - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = $timeout(function() { callback(currTime + timeToCall); }, - timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - - return polyfill('requestAnimationFrame', fallback); -}]) -.factory('cancelAnimation', ["polyfill", "$timeout", function(polyfill, $timeout) { - 'use strict'; - - var fallback = function(promise) { - $timeout.cancel(promise); - }; - - return polyfill('cancelAnimationFrame', fallback); -}]); - - -angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI']) -.factory('spyAPI', ["$rootScope", "$timeout", "scrollContainerAPI", "duScrollGreedy", "duScrollSpyWait", function($rootScope, $timeout, scrollContainerAPI, duScrollGreedy, duScrollSpyWait) { - 'use strict'; - - var createScrollHandler = function(context) { - var timer = false, queued = false; - var handler = function() { - queued = false; - var container = context.container, - containerEl = container[0], - containerOffset = 0; - - if (typeof HTMLElement !== 'undefined' && containerEl instanceof HTMLElement || containerEl.nodeType && containerEl.nodeType === containerEl.ELEMENT_NODE) { - containerOffset = containerEl.getBoundingClientRect().top; - } - - var i, currentlyActive, toBeActive, spies, spy, pos; - spies = context.spies; - currentlyActive = context.currentlyActive; - toBeActive = undefined; - - for(i = 0; i < spies.length; i++) { - spy = spies[i]; - pos = spy.getTargetPosition(); - if (!pos) continue; - - if(pos.top + spy.offset - containerOffset < 20 && (pos.top*-1 + containerOffset) < pos.height) { - if(!toBeActive || toBeActive.top < pos.top) { - toBeActive = { - top: pos.top, - spy: spy - }; - } - } - } - if(toBeActive) { - toBeActive = toBeActive.spy; - } - if(currentlyActive === toBeActive || (duScrollGreedy && !toBeActive)) return; - if(currentlyActive) { - currentlyActive.$element.removeClass('active'); - $rootScope.$broadcast('duScrollspy:becameInactive', currentlyActive.$element); - } - if(toBeActive) { - toBeActive.$element.addClass('active'); - $rootScope.$broadcast('duScrollspy:becameActive', toBeActive.$element); - } - context.currentlyActive = toBeActive; - }; - - if(!duScrollSpyWait) { - return handler; - } - - //Debounce for potential performance savings - return function() { - if(!timer) { - handler(); - timer = $timeout(function() { - timer = false; - if(queued) { - handler(); - } - }, duScrollSpyWait, false); - } else { - queued = true; - } - }; - }; - - var contexts = {}; - - var createContext = function($scope) { - var id = $scope.$id; - var context = { - spies: [] - }; - - context.handler = createScrollHandler(context); - contexts[id] = context; - - $scope.$on('$destroy', function() { - destroyContext($scope); - }); - - return id; - }; - - var destroyContext = function($scope) { - var id = $scope.$id; - var context = contexts[id], container = context.container; - if(container) { - container.off('scroll', context.handler); - } - delete contexts[id]; - }; - - var defaultContextId = createContext($rootScope); - - var getContextForScope = function(scope) { - if(contexts[scope.$id]) { - return contexts[scope.$id]; - } - if(scope.$parent) { - return getContextForScope(scope.$parent); - } - return contexts[defaultContextId]; - }; - - var getContextForSpy = function(spy) { - var context, contextId, scope = spy.$element.scope(); - if(scope) { - return getContextForScope(scope); - } - //No scope, most likely destroyed - for(contextId in contexts) { - context = contexts[contextId]; - if(context.spies.indexOf(spy) !== -1) { - return context; - } - } - }; - - var isElementInDocument = function(element) { - while (element.parentNode) { - element = element.parentNode; - if (element === document) { - return true; - } - } - return false; - }; - - var addSpy = function(spy) { - var context = getContextForSpy(spy); - if (!context) return; - context.spies.push(spy); - if (!context.container || !isElementInDocument(context.container)) { - if(context.container) { - context.container.off('scroll', context.handler); - } - context.container = scrollContainerAPI.getContainer(spy.$element.scope()); - context.container.on('scroll', context.handler).triggerHandler('scroll'); - } - }; - - var removeSpy = function(spy) { - var context = getContextForSpy(spy); - if(spy === context.currentlyActive) { - context.currentlyActive = null; - } - var i = context.spies.indexOf(spy); - if(i !== -1) { - context.spies.splice(i, 1); - } - }; - - return { - addSpy: addSpy, - removeSpy: removeSpy, - createContext: createContext, - destroyContext: destroyContext, - getContextForScope: getContextForScope - }; -}]); - - -angular.module('duScroll.scrollContainerAPI', []) -.factory('scrollContainerAPI', ["$document", function($document) { - 'use strict'; - - var containers = {}; - - var setContainer = function(scope, element) { - var id = scope.$id; - containers[id] = element; - return id; - }; - - var getContainerId = function(scope) { - if(containers[scope.$id]) { - return scope.$id; - } - if(scope.$parent) { - return getContainerId(scope.$parent); - } - return; - }; - - var getContainer = function(scope) { - var id = getContainerId(scope); - return id ? containers[id] : $document; - }; - - var removeContainer = function(scope) { - var id = getContainerId(scope); - if(id) { - delete containers[id]; - } - }; - - return { - getContainerId: getContainerId, - getContainer: getContainer, - setContainer: setContainer, - removeContainer: removeContainer - }; -}]); - - -angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scrollContainerAPI']) -.directive('duSmoothScroll', ["duScrollDuration", "duScrollOffset", "scrollContainerAPI", function(duScrollDuration, duScrollOffset, scrollContainerAPI) { - 'use strict'; - - return { - link : function($scope, $element, $attr) { - $element.on('click', function(e) { - if(!$attr.href || $attr.href.indexOf('#') === -1) return; - - var target = document.getElementById($attr.href.replace(/.*(?=#[^\s]+$)/, '').substring(1)); - if(!target || !target.getBoundingClientRect) return; - - if (e.stopPropagation) e.stopPropagation(); - if (e.preventDefault) e.preventDefault(); - - var offset = $attr.offset ? parseInt($attr.offset, 10) : duScrollOffset; - var duration = $attr.duration ? parseInt($attr.duration, 10) : duScrollDuration; - var container = scrollContainerAPI.getContainer($scope); - - container.scrollToElement( - angular.element(target), - isNaN(offset) ? 0 : offset, - isNaN(duration) ? 0 : duration - ); - }); - } - }; -}]); - - -angular.module('duScroll.spyContext', ['duScroll.spyAPI']) -.directive('duSpyContext', ["spyAPI", function(spyAPI) { - 'use strict'; - - return { - restrict: 'A', - scope: true, - compile: function compile(tElement, tAttrs, transclude) { - return { - pre: function preLink($scope, iElement, iAttrs, controller) { - spyAPI.createContext($scope); - } - }; - } - }; -}]); - - -angular.module('duScroll.scrollContainer', ['duScroll.scrollContainerAPI']) -.directive('duScrollContainer', ["scrollContainerAPI", function(scrollContainerAPI){ - 'use strict'; - - return { - restrict: 'A', - scope: true, - compile: function compile(tElement, tAttrs, transclude) { - return { - pre: function preLink($scope, iElement, iAttrs, controller) { - iAttrs.$observe('duScrollContainer', function(element) { - if(angular.isString(element)) { - element = document.getElementById(element); - } - - element = (angular.isElement(element) ? angular.element(element) : iElement); - scrollContainerAPI.setContainer($scope, element); - $scope.$on('$destroy', function() { - scrollContainerAPI.removeContainer($scope); - }); - }); - } - }; - } - }; -}]); - - -angular.module('duScroll.scrollspy', ['duScroll.spyAPI']) -.directive('duScrollspy', ["spyAPI", "duScrollOffset", "$timeout", "$rootScope", function(spyAPI, duScrollOffset, $timeout, $rootScope) { - 'use strict'; - - var Spy = function(targetElementOrId, $element, offset) { - if(angular.isElement(targetElementOrId)) { - this.target = targetElementOrId; - } else if(angular.isString(targetElementOrId)) { - this.targetId = targetElementOrId; - } - this.$element = $element; - this.offset = offset; - }; - - Spy.prototype.getTargetElement = function() { - if (!this.target && this.targetId) { - this.target = document.getElementById(this.targetId); - } - return this.target; - }; - - Spy.prototype.getTargetPosition = function() { - var target = this.getTargetElement(); - if(target) { - return target.getBoundingClientRect(); - } - }; - - Spy.prototype.flushTargetCache = function() { - if(this.targetId) { - this.target = undefined; - } - }; - - return { - link: function ($scope, $element, $attr) { - var href = $attr.ngHref || $attr.href; - var targetId; - - if (href && href.indexOf('#') !== -1) { - targetId = href.replace(/.*(?=#[^\s]+$)/, '').substring(1); - } else if($attr.duScrollspy) { - targetId = $attr.duScrollspy; - } - if(!targetId) return; - - // Run this in the next execution loop so that the scroll context has a chance - // to initialize - $timeout(function() { - var spy = new Spy(targetId, $element, -($attr.offset ? parseInt($attr.offset, 10) : duScrollOffset)); - spyAPI.addSpy(spy); - - $scope.$on('$destroy', function() { - spyAPI.removeSpy(spy); - }); - $scope.$on('$locationChangeSuccess', spy.flushTargetCache.bind(spy)); - $rootScope.$on('$stateChangeSuccess', spy.flushTargetCache.bind(spy)); - }, 0, false); - } - }; -}]); diff --git a/app/assets/javascripts/angularjs.js.coffee b/app/assets/javascripts/angularjs.js.coffee deleted file mode 100644 index e07f15b..0000000 --- a/app/assets/javascripts/angularjs.js.coffee +++ /dev/null @@ -1,15 +0,0 @@ -#= require angular -#= require angular-cookies -#= require angular-resource -#= require angular-sanitize -#= require angular-scroll -#= require_self -#= require_tree ./angularjs - -@app = angular.module('app', ['ngCookies', 'ngSanitize', 'duScroll']) -@app.value('duScrollOffset', 30) - -@app.config(["$httpProvider", (provider) -> - provider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content') - provider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest' -]) diff --git a/app/assets/javascripts/angularjs/about.js.coffee b/app/assets/javascripts/angularjs/about.js.coffee deleted file mode 100644 index 58ef59c..0000000 --- a/app/assets/javascripts/angularjs/about.js.coffee +++ /dev/null @@ -1,36 +0,0 @@ -@app.controller 'AboutController', [ '$scope', '$timeout', '$http', ($scope, $timeout, $http)-> - $scope.type = null - - $scope.click = (v)-> - if $scope.type == v - $scope.type = null - return - $scope.type = v - $scope.weixin_click = -> - $scope.weixin = !$scope.weixin - - #订阅功能 - - $scope.email = '' - $scope.subscribe_success = null - - $scope.email_validate = -> - $scope.email.match(/@/) - - $scope.subscribe = ()-> - $http - url: '/subscribes' - method: 'POST' - params: - email: $scope.email - .success (res)-> - if res.success - $scope.email = '' - $scope.subscribe_success = true - else - $scope.subscribe_success = false - $scope.subscribe_fail_msg = res.message - $timeout -> - $scope.subscribe_success = null - , 3000 -] diff --git a/app/assets/javascripts/angularjs/about_scroll.js.coffee b/app/assets/javascripts/angularjs/about_scroll.js.coffee deleted file mode 100644 index 0c8fdd4..0000000 --- a/app/assets/javascripts/angularjs/about_scroll.js.coffee +++ /dev/null @@ -1,14 +0,0 @@ -@app.controller 'AboutScrollController', [ '$scope', '$document', ($scope, $document)-> - - about_id = angular.element(document.getElementById('about')) - - $document.on 'scroll', ()=> - $scope.$apply() - - $scope.is_top = ()-> - $document.scrollTop() <= 0 - - - $scope.to_about = ()-> - $document.scrollToElementAnimated(about_id) -] diff --git a/app/assets/javascripts/angularjs/admin_sessions.js.coffee b/app/assets/javascripts/angularjs/admin_sessions.js.coffee deleted file mode 100644 index 51a4aeb..0000000 --- a/app/assets/javascripts/angularjs/admin_sessions.js.coffee +++ /dev/null @@ -1,21 +0,0 @@ -@app.controller 'AdminSessionsController', [ '$scope', '$http', '$timeout', '$cookies', ($scope, $http, $timeout, $cookies)-> - url = '/admin/sessions' - - $scope.login = -> - $http - url: url - method: 'POST' - data: - username: $scope.username - password: $scope.password - .success (res)-> - if res.success - urlback = $cookies.urlback || '/admin' - window.location = urlback - else - $scope.password = '' - $scope.error_msg = res.message - $timeout -> - $scope.error_msg = null - , 5000 -] diff --git a/app/assets/javascripts/angularjs/archives.js.coffee b/app/assets/javascripts/angularjs/archives.js.coffee deleted file mode 100644 index d93e654..0000000 --- a/app/assets/javascripts/angularjs/archives.js.coffee +++ /dev/null @@ -1,43 +0,0 @@ -@app.controller 'ArchivesController',[ '$scope', '$http', '$location', '$timeout', '$cookies', ($scope, $http, $location, $timeout, $cookies)-> - url = window.location.pathname + ".json" - start_with = $cookies.start_with if window.location.pathname == $cookies.start_with_type - $http - url: url - method: 'GET' - params: - start_with: start_with - all: true - .success (res)-> - $scope.update_start_with(res.start_with) - $scope.posts = res.posts - - $scope.no_more_flag = false - $scope.loading_flag = false - - $scope.load = ()-> - $scope.loading_flag = true - $http( - url: url - method: 'GET' - params: - start_with: $scope.start_with - type: $scope.type - ).success (res)-> - $scope.no_more_flag = true if res.posts.length == 0 - $scope.update_start_with(res.start_with) - $scope.posts = $scope.posts.concat(res.posts) - $timeout -> - $scope.loading_flag = false - , 500 - $timeout -> - $scope.no_more_flag = false - , 3000 - - $scope.visit = (id)-> - "/blogs/" + id - - $scope.update_start_with = (start_with)-> - $scope.start_with = start_with - $cookies.start_with_type = window.location.pathname - $cookies.start_with = start_with -] diff --git a/app/assets/javascripts/angularjs/comments.js.coffee b/app/assets/javascripts/angularjs/comments.js.coffee deleted file mode 100644 index e83fc29..0000000 --- a/app/assets/javascripts/angularjs/comments.js.coffee +++ /dev/null @@ -1,35 +0,0 @@ -@app.controller 'CommentsController', ['$scope', '$http', '$location', '$timeout', '$cookies', ($scope, $http, $location, $timeout, $cookies)-> - url = window.location.pathname + "/comments.json" - - $scope.name = $cookies.name - $scope.email = $cookies.email - - $http.get(url).success (data)-> - $scope.comments = data - - $scope.publish_success = null - - $scope.submit = -> - $scope.submitting = true - $cookies.name = $scope.name - $cookies.email = $scope.email - comment = { content: $scope.content, name: $scope.name, email: $scope.email } - $http.post(url, comment) - .success (res)-> - if res.success - $scope.publish_success = true - $scope.content = '' - $scope.comments.unshift(res.data) - else - $scope.publish_success = false - $scope.publish_fail_msg = res.message - .error (data, status)-> - $scope.publish_success = false - $scope.publish_fail_msg = 'Network Error, Retry for a moment, Status Code: ' + status - .finally -> - $scope.submitting = false - $scope.timeout = $timeout -> - $timeout.cancel($scope.timeout) - $scope.publish_success = null - , 5*1000 -] diff --git a/app/assets/javascripts/angularjs/directives.js.coffee b/app/assets/javascripts/angularjs/directives.js.coffee deleted file mode 100644 index 50d1cf8..0000000 --- a/app/assets/javascripts/angularjs/directives.js.coffee +++ /dev/null @@ -1,9 +0,0 @@ -@app.directive 'ngInitial', -> - restrict: 'A', - controller: [ - '$scope', '$element', '$attrs', '$parse', ($scope, $element, $attrs, $parse)-> - val = $attrs.ngInitial || $attrs.value || $attrs.$$element.text() - getter = $parse($attrs.ngModel) - setter = getter.assign - setter($scope, val) - ] diff --git a/app/assets/javascripts/angularjs/likes.js.coffee b/app/assets/javascripts/angularjs/likes.js.coffee deleted file mode 100644 index d79010c..0000000 --- a/app/assets/javascripts/angularjs/likes.js.coffee +++ /dev/null @@ -1,38 +0,0 @@ -@app.controller 'LikesController', ['$scope', '$http', '$location', '$cookies', ($scope, $http, $location, $cookies)-> - url = window.location.pathname + "/likes" - - $http.get url - .success (res)-> - $scope.count = res.count - - $scope.like = $cookies.like - - if $scope.like - $http - url: window.location.pathname + "/likes/#{$scope.like}/is_liked" - method: 'GET' - .success (res)-> - if res == true - $scope.is_liked = true - else - $scope.is_liked = false - else - $scope.is_liked = false - - $scope.submit = -> - $http.post url - .success (res)-> - if res.success - $scope.like = $cookies.like = res.id - $scope.count = res.count - $scope.is_liked = true - - $scope.cancel = -> - $http.delete url + "/" + $scope.like - .success (res)-> - $scope.count = res.count - $scope.is_liked = false - # anyway, clear cookie - delete $cookies["like"] - $scope.like = null -] diff --git a/app/assets/javascripts/angularjs/qrcodes.js.coffee b/app/assets/javascripts/angularjs/qrcodes.js.coffee deleted file mode 100644 index e95ec76..0000000 --- a/app/assets/javascripts/angularjs/qrcodes.js.coffee +++ /dev/null @@ -1,4 +0,0 @@ -@app.controller 'QRCodesController', [ '$scope', ($scope)-> - $scope.show = -> - $scope.qrcode = ! $scope.qrcode -] diff --git a/app/assets/javascripts/angularjs/subscribes.js.coffee b/app/assets/javascripts/angularjs/subscribes.js.coffee deleted file mode 100644 index 04bf07a..0000000 --- a/app/assets/javascripts/angularjs/subscribes.js.coffee +++ /dev/null @@ -1,10 +0,0 @@ -@app.controller 'SubscribesController', [ '$scope', '$http', ($scope, $http)-> - $scope.cancel = ()-> - $http - url: '/subscribes/cancel' - method: 'POST' - params: - email: $scope.email - .success (res)-> - window.location = '/' -] diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e2bb1c0..37173a7 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,9 +1,10 @@ //= require jquery //= require jquery_ujs +//= require turbolinks //= require foundation -//= require angularjs //= require 'jquery.html5-fileupload' //= require_tree . - -$(function(){ $(document).foundation(); }); +$(document).on('turbolinks:load', function(){ + $(document).foundation(); +}); diff --git a/app/assets/javascripts/qrcode.js.coffee b/app/assets/javascripts/qrcode.js.coffee index 17a7a06..f049ae8 100644 --- a/app/assets/javascripts/qrcode.js.coffee +++ b/app/assets/javascripts/qrcode.js.coffee @@ -1,4 +1,4 @@ -$(document).ready ()-> +$(document).on 'turbolinks:load', -> $('#qrcode-link').click (event)-> event.preventDefault() $('.social-share').toggle() diff --git a/app/assets/stylesheets/angularjs.scss b/app/assets/stylesheets/angularjs.scss deleted file mode 100644 index f761505..0000000 --- a/app/assets/stylesheets/angularjs.scss +++ /dev/null @@ -1,3 +0,0 @@ -.ng-dirty .ng-invalid, .ng-dirty .ng-required { - border: 1px solid #FF7A7A !important; -} diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 78f64db..378b8c4 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -9,9 +9,14 @@ @import 'blogs'; @import 'head'; @import 'qrcodes'; -@import 'angularjs'; @import 'comments'; @import 'highlight'; @import 'footer'; @import 'like_and_weixin'; @import 'admin/*'; + +.turbolinks-progress-bar { + height: 2px; + background-color: red; +} + diff --git a/app/controllers/archives_controller.rb b/app/controllers/archives_controller.rb index c89c371..ebb6e06 100644 --- a/app/controllers/archives_controller.rb +++ b/app/controllers/archives_controller.rb @@ -1,5 +1,5 @@ class ArchivesController < ApplicationController def index - @posts = Post.order(created_at: :desc) + @posts = Post.order(created_at: :desc).page(params[:page]).per(3) end end diff --git a/app/views/archives/index.html.slim b/app/views/archives/index.html.slim index a5ba485..b107daa 100644 --- a/app/views/archives/index.html.slim +++ b/app/views/archives/index.html.slim @@ -19,3 +19,4 @@ i.fi-heart span = post.liked_count + = paginate @posts diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 0d2c457..b963ea4 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -6,9 +6,9 @@ html = yield(:meta) title = content_for?(:title) ? yield(:title) + " | #{ENV['SITE_NAME']}" : ENV['SITE_NAME'] - = stylesheet_link_tag "application", media: 'all' + = stylesheet_link_tag "application", 'data-turbolinks-track' => "reload" = favicon_link_tag 'favicon.png', type: 'image/png' - = javascript_include_tag "application" + = javascript_include_tag "application", 'data-turbolinks-track' => "reload" = csrf_meta_tags body data-whatinput="mouse" - if content_for?(:main) diff --git a/config/database.yml.example b/config/database.yml.example new file mode 100644 index 0000000..a4e34ca --- /dev/null +++ b/config/database.yml.example @@ -0,0 +1,20 @@ +development: + adapter: postgresql + host: localhost + encoding: unicode + database: wblog_development + pool: 5 + +test: + adapter: postgresql + host: localhost + encoding: unicode + database: wblog_test + pool: 5 + +production: + adapter: postgresql + host: localhost + encoding: unicode + database: wblog_production + pool: 5 diff --git a/config/mongoid.yml.example b/config/mongoid.yml.example deleted file mode 100644 index 716a78b..0000000 --- a/config/mongoid.yml.example +++ /dev/null @@ -1,29 +0,0 @@ -development: - clients: - default: - database: w_blog_development - hosts: - - localhost:27017 - options: - -production: - clients: - default: - database: w_blog_production - hosts: - - localhost:27017 - options: - -test: - clients: - default: - database: w_blog_test - hosts: - - localhost:27017 - options: - read: - mode: :primary - # In the test environment we lower the retries and retry interval to - # low amounts for fast failures. - max_retries: 1 - retry_interval: 0 diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..604e784 --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,8 @@ +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i +threads threads_count, threads_count + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +plugin :tmp_restart From e1060b93afb07265165c5a92e1f04bb1517b62fd Mon Sep 17 00:00:00 2001 From: yafeilee Date: Thu, 21 Apr 2016 22:11:18 +0800 Subject: [PATCH 07/14] Like feature done --- Gemfile | 1 + Gemfile.lock | 5 +++-- app/assets/javascripts/application.js | 1 + app/assets/javascripts/jquery.atwho.js | 11 ++--------- app/assets/javascripts/like.js.coffee | 19 +++++++++++++++++++ app/controllers/archives_controller.rb | 2 +- app/controllers/likes_controller.rb | 9 --------- app/models/post.rb | 4 ++++ app/views/blogs/_post.html.slim | 5 +++-- 9 files changed, 34 insertions(+), 23 deletions(-) mode change 100755 => 100644 app/assets/javascripts/jquery.atwho.js create mode 100644 app/assets/javascripts/like.js.coffee diff --git a/Gemfile b/Gemfile index 45e1fcb..4c497ba 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,7 @@ gem 'font-awesome-sass' gem 'carrierwave' gem 'kaminari', git: 'git@github.com:amatsuda/kaminari.git' gem 'turbolinks', '~> 5.x' +gem 'js_cookie_rails' gem 'jbuilder' gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index d5255e9..e80c6f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -47,7 +47,6 @@ GEM minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.4.0) - angularjs-rails (1.5.0) arel (7.0.0) babel-source (5.8.35) babel-transpiler (0.7.0) @@ -135,6 +134,8 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) + js_cookie_rails (1.0.1) + railties (>= 3.1) json (1.8.3) listen (3.0.6) rb-fsevent (>= 0.9.3) @@ -318,7 +319,6 @@ PLATFORMS ruby DEPENDENCIES - angularjs-rails byebug capybara carrierwave @@ -337,6 +337,7 @@ DEPENDENCIES html_truncator jbuilder jquery-rails + js_cookie_rails kaminari! listen (~> 3.0.5) mina diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 37173a7..69eacbe 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -2,6 +2,7 @@ //= require jquery_ujs //= require turbolinks //= require foundation +//= require js.cookie //= require 'jquery.html5-fileupload' //= require_tree . diff --git a/app/assets/javascripts/jquery.atwho.js b/app/assets/javascripts/jquery.atwho.js old mode 100755 new mode 100644 index 1576122..cb55699 --- a/app/assets/javascripts/jquery.atwho.js +++ b/app/assets/javascripts/jquery.atwho.js @@ -8,13 +8,6 @@ */ -/* -本插件操作 textarea 或者 input 内的插入符 -只实现了获得插入符在文本框中的位置,我设置 -插入符的位置. -*/ - - (function() { (function(factory) { if (typeof define === 'function' && define.amd) { @@ -85,7 +78,7 @@ / \ < I really [[HATE] IE []]> \_endRange end-point. - + " > -1" mean the start end-point will be the same or right to the end end-point * simplelly, all in the end. */ @@ -99,7 +92,7 @@ I really[ [HATE] IE ]> <-[ I reall[y [HATE] IE ]> - + will return how many unit have moved. */ diff --git a/app/assets/javascripts/like.js.coffee b/app/assets/javascripts/like.js.coffee new file mode 100644 index 0000000..0f04445 --- /dev/null +++ b/app/assets/javascripts/like.js.coffee @@ -0,0 +1,19 @@ +$(document).on 'turbolinks:load', -> + + $('.like-button').click -> + if $(this).hasClass('liked') + $.ajax + url: $(this).data('url') + '/' + Cookies.get('like') + type: 'DELETE' + success: (res)=> + $(this).removeClass('liked') + $(this).children('.count').text(res.count) + Cookies.remove('like') + else + $.ajax + url: $(this).data('url') + type: 'POST' + success: (res)=> + $(this).addClass('liked') + $(this).children('.count').text(res.count) + Cookies.set('like', res.id) diff --git a/app/controllers/archives_controller.rb b/app/controllers/archives_controller.rb index ebb6e06..059896d 100644 --- a/app/controllers/archives_controller.rb +++ b/app/controllers/archives_controller.rb @@ -1,5 +1,5 @@ class ArchivesController < ApplicationController def index - @posts = Post.order(created_at: :desc).page(params[:page]).per(3) + @posts = Post.order(created_at: :desc).page(params[:page]) end end diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb index 4e6e9e3..63e38ca 100644 --- a/app/controllers/likes_controller.rb +++ b/app/controllers/likes_controller.rb @@ -6,15 +6,6 @@ class LikesController < ApplicationController render :json=> { success: true, count: post.liked_count } end - def is_liked - post = Post.find( params[:blog_id] ) - if post.likes.where(id: params[:id]).first - render text: true - else - render text: false - end - end - def create post = Post.find( params[:blog_id] ) like = post.likes.build diff --git a/app/models/post.rb b/app/models/post.rb index 3ecb973..d5fe8c4 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -52,4 +52,8 @@ class Post < ActiveRecord::Base def liked_count self.likes.size end + + def liked_by?(like_id) + !! self.likes.where(id: like_id).first + end end diff --git a/app/views/blogs/_post.html.slim b/app/views/blogs/_post.html.slim index ab1635d..557c9ce 100644 --- a/app/views/blogs/_post.html.slim +++ b/app/views/blogs/_post.html.slim @@ -10,8 +10,9 @@ p.ptag.published-at = render 'common/copyright' hr.blog-over p - button.button.like-button type='button' - | #{@likes_count} Like + button.button.like-button class="#{'liked' if post.liked_by?(cookies[:like])}" type='button' data-url=blog_likes_path(post) + span.count #{@likes_count} + span Like .qrcode a#qrcode-link href="#" i.fi-link From 6bf723a3f7257b803afde64c93d4189bb8f7772d Mon Sep 17 00:00:00 2001 From: yafeilee Date: Thu, 21 Apr 2016 23:58:24 +0800 Subject: [PATCH 08/14] about page refactor --- app/assets/javascripts/about.js.coffee | 13 ++ app/assets/javascripts/ddscrollspy.js | 225 ++++++++++++++++++++ app/assets/stylesheets/aboutme_welcome.scss | 16 +- app/views/home/index.html.slim | 28 +-- 4 files changed, 266 insertions(+), 16 deletions(-) create mode 100644 app/assets/javascripts/about.js.coffee create mode 100644 app/assets/javascripts/ddscrollspy.js diff --git a/app/assets/javascripts/about.js.coffee b/app/assets/javascripts/about.js.coffee new file mode 100644 index 0000000..6a727f0 --- /dev/null +++ b/app/assets/javascripts/about.js.coffee @@ -0,0 +1,13 @@ +$(document).on 'turbolinks:load', -> + if $('.about-page').length > 0 + $(window).scroll ()-> + if $(this).scrollTop() > 0 + $('.top-bar-wrapper').addClass('active') + else + $('.top-bar-wrapper').removeClass('active') + + $('#about-top-bar').ddscrollSpy + highlightclass: 'active' + + $('.intro').ddscrollSpy + highlightclass: 'active' diff --git a/app/assets/javascripts/ddscrollspy.js b/app/assets/javascripts/ddscrollspy.js new file mode 100644 index 0000000..98376e3 --- /dev/null +++ b/app/assets/javascripts/ddscrollspy.js @@ -0,0 +1,225 @@ +/* +* DD ScrollSpy Menu Script (c) Dynamic Drive (www.dynamicdrive.com) +* Last updated: Aug 1st, 14' +* Visit http://www.dynamicdrive.com/ for this script and 100s more. +*/ + +// Aug 1st, 14': Updated to v1.2, which supports showing a progress bar inside each menu item (except in iOS devices). Other minor improvements. + +if (!Array.prototype.filter){ + Array.prototype.filter = function(fun /*, thisp */){ + "use strict"; + + if (this == null) + throw new TypeError(); + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") + throw new TypeError(); + + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++){ + if (i in t){ + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } + + return res; + }; +} + +(function($){ + + var defaults = { + spytarget: window, + scrolltopoffset: 0, + scrollbehavior: 'smooth', + scrollduration: 500, + highlightclass: 'selected', + enableprogress: '', + mincontentheight: 30 + } + + var isiOS = /iPhone|iPad|iPod/i.test(navigator.userAgent) // detect iOS devices + + function inrange(el, range, field){ // check if "playing field" is inside range + var rangespan = range[1]-range[0], fieldspan = field[1]-field[0] + if ( (range[0]-field[0]) >= 0 && (range[0]-field[0]) < fieldspan ){ // if top of range is on field + return true + } + else{ + if ( (range[0]-field[0]) <= 0 && (range[0]+rangespan) > field[0] ){ // if part of range overlaps field + return true + } + } + return false + } + + $.fn.ddscrollSpy = function(options){ + var $window = $(window) + var $body=(window.opera)? (document.compatMode=="CSS1Compat"? $('html') : $('body')) : $('html,body') + + + return this.each(function(){ + var o = $.extend({}, defaults, options) + o.enableprogress = (isiOS)? '' : o.enableprogress // disable enableprogress in iOS + var targets = [], curtarget = '' + var cantscrollpastindex = -1 // index of target content that can't be scrolled past completely when scrollbar is at the end of the doc + var $spytarget = $( o.spytarget ).eq(0) + var spyheight = $spytarget.outerHeight() + var spyscrollheight = (o.spytarget == window)? $body.get(0).scrollHeight : $spytarget.get(0).scrollHeight + var $menu = $(this) + var totaltargetsheight = 0 // total height of target contents + function spyonmenuitems($menu){ + var $menuitems = $menu.find('a[href^="#"]') + targets = [] + curtarget = '' + totaltargetsheight = 0 + $menuitems.each(function(i){ + var $item = $(this) + var $target = $( $item.attr('href') ) + var target = $target.get(0) + var $progress = null // progress DIV that gets dynamically added inside menu A element if o.enableprogress enabled + if ($target.length == 0) // if no matching links found + return true + $item + .off('click.goto') + .on('click.goto', function(e){ + if ( o.spytarget == window && (o.scrollbehavior == 'jump' || !history.pushState)) + window.location.hash = $item.attr('href') + if (o.scrollbehavior == 'smooth' || o.scrolltopoffset !=0){ + var $scrollparent = (o.spytarget == window)? $body : $spytarget + var addoffset = 1 // add 1 pixel to scrollTop when scrolling to an element to make sure the browser always returns the correct target element (strange bug) + if (o.scrollbehavior == 'smooth' && (history.pushState || o.spytarget != window)){ + $scrollparent.animate( {scrollTop: targets[i].offsettop + addoffset}, o.scrollduration, function(){ + if (o.spytarget == window && history.pushState){ + //history.pushState(null, null, $item.attr('href')) + } + }) + } + else{ + $scrollparent.prop('scrollTop', targets[i].offsettop + addoffset) + } + e.preventDefault() + } + }) + if (o.enableprogress){ // if o.enableprogress enabled + if ($item.find('div.' + o.enableprogress).length == 0){ //if no progress DIV found inside menu item + $item.css({position: 'relative', overflow: 'hidden'}) // add some required style to parent A element + $('
').appendTo($item) + } + $progress = $item.find('div.' + o.enableprogress) + } + var targetoffset = (o.spytarget == window)? $target.offset().top : (target.offsetParent == o.spytarget)? target.offsetTop : target.offsetTop - o.spytarget.offsetTop + targetoffset += o.scrolltopoffset + var targetheight = ( parseInt($target.data('spyrange')) > 0 )? parseInt($target.data('spyrange')) : ( $target.outerHeight() || o.mincontentheight) + var offsetbottom = targetoffset + targetheight + if (cantscrollpastindex == -1 && offsetbottom > (spyscrollheight - spyheight)){ // determine index of first target which can't be scrolled past + cantscrollpastindex = i + } + targets.push( {$menuitem: $item, $des: $target, offsettop: targetoffset, height: targetheight, $progress: $progress, index: i} ) + }) + if (targets.length > 0) + totaltargetsheight = targets[targets.length-1].offsettop + targets[targets.length-1].height + } + + function highlightitem(){ + if (targets.length == 0) + return + var prevtarget = curtarget + var scrolltop = $spytarget.scrollTop() + var cantscrollpasttarget = false + var shortlist = targets.filter(function(el, index){ // filter target elements that are currently visible on screen + return inrange(el, [el.offsettop, el.offsettop + el.height], [scrolltop, scrolltop + spyheight]) + }) + if (shortlist.length > 0){ + curtarget = shortlist.shift() // select the first element that's visible on screen + if (prevtarget && prevtarget != curtarget) + prevtarget.$menuitem.removeClass(o.highlightclass) + if (!curtarget.$menuitem.hasClass(o.highlightclass)) // if there was a previously selected menu link and it's not the same as current + curtarget.$menuitem.addClass(o.highlightclass) // highlight its menu item + if (curtarget.index >= cantscrollpastindex && scrolltop >= (spyscrollheight - spyheight)){ // if we're at target that can't be scrolled past and we're at end of document + if (o.enableprogress){ // if o.enableprogress enabled + for (var i=0; i curtarget.index){ + targets[i].$menuitem.find('div.' + o.enableprogress).css('left', '-100%') + } + } + } + } + else if (scrolltop > totaltargetsheight){ // if no target content visible on screen but scroll bar has scrolled past very last content already + if (o.enableprogress){ // if o.enableprogress enabled + curtarget.$menuitem.removeClass(o.highlightclass) + for (var i=0; i 0 )? parseInt($target.data('spyrange')) : ( $target.outerHeight() || o.mincontentheight) + if (o.enableprogress){ // if o.enableprogress enabled + var offsetbottom = targetoffset + targets[i].height // recalculate cantscrollpastindex + if (cantscrollpastindex == -1 && offsetbottom > (spyscrollheight - spyheight)){ + cantscrollpastindex = i + } + } + } + totaltargetsheight = targets[targets.length-1].offsettop + targets[targets.length-1].height + } + + spyonmenuitems($menu) + + $menu.on('updatespy', function(){ + spyonmenuitems($menu) + highlightitem() + }) + + $spytarget.on('scroll resize', function(){ + highlightitem() + }) + + highlightitem() + + $window.on('load resize', function(){ + updatetargetpos() + }) + + }) // end return + } + +})(jQuery); diff --git a/app/assets/stylesheets/aboutme_welcome.scss b/app/assets/stylesheets/aboutme_welcome.scss index c33a9ca..07e70d7 100644 --- a/app/assets/stylesheets/aboutme_welcome.scss +++ b/app/assets/stylesheets/aboutme_welcome.scss @@ -23,6 +23,14 @@ .about-page { + .fixed { + position: fixed; + top: 0; + width: 100%; + z-index: 99; + left: 0; + } + a { word-wrap: break-word; } @@ -42,15 +50,19 @@ .top-bar { background: 0 0; margin: 1.5rem 0; - .name h1 { + .name { font-size: 1.325rem; } } - .top-bar-section ul{ + .top-bar ul{ + & { + background: 0 0; + } li, li a { background: 0 0; font-size: 1rem; + color: #fefefe; } li a:hover { diff --git a/app/views/home/index.html.slim b/app/views/home/index.html.slim index db7a87a..51bdfff 100644 --- a/app/views/home/index.html.slim +++ b/app/views/home/index.html.slim @@ -1,25 +1,25 @@ - content_for(:title) do | #{t('title.about')} - content_for(:main) do - .about-page ng-app='app' ng-controller='AboutScrollController' - .top-bar-wrapper.contain-to-grid.fixed ng-class="{ active: ! is_top() }" + .about-page + .top-bar-wrapper.contain-to-grid.fixed .row .small-12.columns - nav.top-bar data-topbar='' role='navigation' - ul.title-area - li.name - h1 - a href='/' 回到博客 - section.top-bar-section - ul.right + nav#about-top-bar.top-bar + .top-bar-left + ul.menu li - a href='#about' du-smooth-scroll='' du-scrollspy='' 关于 + a.name href='/' 回到博客 + .top-bar-right + ul.menu li - a href='#skill' du-smooth-scroll='' du-scrollspy='' 技能 + a href='#about' 关于 li - a href='#work' du-smooth-scroll='' du-scrollspy='' 作品 + a href='#skill' 技能 li - a href='#contact' du-smooth-scroll='' du-scrollspy='' 联系 + a href='#work' 作品 + li + a href='#contact' 联系 #intro header.intro .intro-heading @@ -32,7 +32,7 @@ | 懒, 是人类进步的动力 br | 所谓技术, 就是让你的生活越来越懒 - a.circle href='#about' du-smooth-scroll='' + a.circle href='#about' i.fa.fa-angle-double-down section#about .row From c749707d9809988ed3683d1bac17464052af5fb1 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Sat, 23 Apr 2016 14:47:50 +0800 Subject: [PATCH 09/14] Refactor comment and qrcode --- Gemfile | 2 + Gemfile.lock | 4 + app/assets/javascripts/comment.js.coffee | 3 + app/assets/javascripts/qrcode.js | 614 ++++++++++++++++++ .../{qrcode.js.coffee => qrcode_op.js.coffee} | 2 + app/assets/stylesheets/comments.scss | 8 +- app/assets/stylesheets/qrcodes.scss | 22 +- app/controllers/blogs_controller.rb | 2 +- app/controllers/comments_controller.rb | 13 +- app/helpers/application_helper.rb | 4 +- app/views/blogs/_comment.html.slim | 24 +- app/views/blogs/_qrcode.html.slim | 2 +- app/views/blogs/show.html.slim | 4 +- app/views/comments/_comment_content.html.slim | 10 + app/views/comments/create_fail.js.erb | 2 + app/views/comments/create_ok.js.erb | 4 + config/locales/zh-CN.yml | 2 +- 17 files changed, 673 insertions(+), 49 deletions(-) create mode 100644 app/assets/javascripts/comment.js.coffee create mode 100644 app/assets/javascripts/qrcode.js rename app/assets/javascripts/{qrcode.js.coffee => qrcode_op.js.coffee} (57%) create mode 100644 app/views/comments/_comment_content.html.slim create mode 100644 app/views/comments/create_fail.js.erb create mode 100644 app/views/comments/create_ok.js.erb diff --git a/Gemfile b/Gemfile index 4c497ba..02e6225 100644 --- a/Gemfile +++ b/Gemfile @@ -16,6 +16,8 @@ gem 'kaminari', git: 'git@github.com:amatsuda/kaminari.git' gem 'turbolinks', '~> 5.x' gem 'js_cookie_rails' +gem 'rails-i18n', '~> 5.0.0.beta3' + gem 'jbuilder' gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index e80c6f8..ffc774e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -206,6 +206,9 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) + rails-i18n (5.0.0.beta3) + i18n (~> 0.7) + railties (~> 5.0.0.beta1) railties (5.0.0.beta3) actionpack (= 5.0.0.beta3) activesupport (= 5.0.0.beta3) @@ -354,6 +357,7 @@ DEPENDENCIES quiet_assets rack-cors rails (>= 5.0.0.beta3, < 5.1) + rails-i18n (~> 5.0.0.beta3) redcarpet redis-namespace rest-client diff --git a/app/assets/javascripts/comment.js.coffee b/app/assets/javascripts/comment.js.coffee new file mode 100644 index 0000000..1794d7c --- /dev/null +++ b/app/assets/javascripts/comment.js.coffee @@ -0,0 +1,3 @@ +$(document).on 'turbolinks:load', -> + $('#alert-container .close-button').click ()-> + $('#alert-container').hide() diff --git a/app/assets/javascripts/qrcode.js b/app/assets/javascripts/qrcode.js new file mode 100644 index 0000000..5507c15 --- /dev/null +++ b/app/assets/javascripts/qrcode.js @@ -0,0 +1,614 @@ +/** + * @fileoverview + * - Using the 'QRCode for Javascript library' + * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. + * - this library has no dependencies. + * + * @author davidshimjs + * @see http://www.d-project.com/ + * @see http://jeromeetienne.github.com/jquery-qrcode/ + */ +var QRCode; + +(function () { + //--------------------------------------------------------------------- + // QRCode for JavaScript + // + // Copyright (c) 2009 Kazuhiko Arase + // + // URL: http://www.d-project.com/ + // + // Licensed under the MIT license: + // http://www.opensource.org/licenses/mit-license.php + // + // The word "QR Code" is registered trademark of + // DENSO WAVE INCORPORATED + // http://www.denso-wave.com/qrcode/faqpatent-e.html + // + //--------------------------------------------------------------------- + function QR8bitByte(data) { + this.mode = QRMode.MODE_8BIT_BYTE; + this.data = data; + this.parsedData = []; + + // Added to support UTF-8 Characters + for (var i = 0, l = this.data.length; i < l; i++) { + var byteArray = []; + var code = this.data.charCodeAt(i); + + if (code > 0x10000) { + byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18); + byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12); + byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[3] = 0x80 | (code & 0x3F); + } else if (code > 0x800) { + byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12); + byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[2] = 0x80 | (code & 0x3F); + } else if (code > 0x80) { + byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6); + byteArray[1] = 0x80 | (code & 0x3F); + } else { + byteArray[0] = code; + } + + this.parsedData.push(byteArray); + } + + this.parsedData = Array.prototype.concat.apply([], this.parsedData); + + if (this.parsedData.length != this.data.length) { + this.parsedData.unshift(191); + this.parsedData.unshift(187); + this.parsedData.unshift(239); + } + } + + QR8bitByte.prototype = { + getLength: function (buffer) { + return this.parsedData.length; + }, + write: function (buffer) { + for (var i = 0, l = this.parsedData.length; i < l; i++) { + buffer.put(this.parsedData[i], 8); + } + } + }; + + function QRCodeModel(typeNumber, errorCorrectLevel) { + this.typeNumber = typeNumber; + this.errorCorrectLevel = errorCorrectLevel; + this.modules = null; + this.moduleCount = 0; + this.dataCache = null; + this.dataList = []; + } + + QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);} + return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row=7){this.setupTypeNumber(test);} + if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);} + this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}} + return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;} + for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}} + for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}} + this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex>>bitIndex)&1)==1);} + var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;} + this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}} + row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;itotalDataCount*8){throw new Error("code length overflow. (" + +buffer.getLengthInBits() + +">" + +totalDataCount*8 + +")");} + if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);} + while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);} + while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD1,8);} + return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r=0)?modPoly.get(modIndex):0;}} + var totalCodeCount=0;for(var i=0;i=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));} + return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));} + return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;} + return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i5){lostPoint+=(3+sameCount-5);}}} + for(var row=0;row=256){n-=255;} + return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);} + if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));} + this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]]; + + function _isSupportCanvas() { + return typeof CanvasRenderingContext2D != "undefined"; + } + + // android 2.x doesn't support Data-URI spec + function _getAndroid() { + var android = false; + var sAgent = navigator.userAgent; + + if (/android/i.test(sAgent)) { // android + android = true; + var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i); + + if (aMat && aMat[1]) { + android = parseFloat(aMat[1]); + } + } + + return android; + } + + var svgDrawer = (function() { + + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + + this.clear(); + + function makeSVG(tag, attrs) { + var el = document.createElementNS('http://www.w3.org/2000/svg', tag); + for (var k in attrs) + if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]); + return el; + } + + var svg = makeSVG("svg" , {'viewBox': '0 0 ' + String(nCount) + " " + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight}); + svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"); + _el.appendChild(svg); + + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorLight, "width": "100%", "height": "100%"})); + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorDark, "width": "1", "height": "1", "id": "template"})); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + if (oQRCode.isDark(row, col)) { + var child = makeSVG("use", {"x": String(col), "y": String(row)}); + child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template") + svg.appendChild(child); + } + } + } + }; + Drawing.prototype.clear = function () { + while (this._el.hasChildNodes()) + this._el.removeChild(this._el.lastChild); + }; + return Drawing; + })(); + + var useSVG = document.documentElement.tagName.toLowerCase() === "svg"; + + // Drawing in DOM by using Table tag + var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () { + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + var aHTML = ['']; + + for (var row = 0; row < nCount; row++) { + aHTML.push(''); + + for (var col = 0; col < nCount; col++) { + aHTML.push(''); + } + + aHTML.push(''); + } + + aHTML.push('
'); + _el.innerHTML = aHTML.join(''); + + // Fix the margin values as real size. + var elTable = _el.childNodes[0]; + var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2; + var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2; + + if (nLeftMarginTable > 0 && nTopMarginTable > 0) { + elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px"; + } + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._el.innerHTML = ''; + }; + + return Drawing; + })() : (function () { // Drawing in Canvas + function _onMakeImage() { + this._elImage.src = this._elCanvas.toDataURL("image/png"); + this._elImage.style.display = "block"; + this._elCanvas.style.display = "none"; + } + + // Android 2.1 bug workaround + // http://code.google.com/p/android/issues/detail?id=5141 + if (this._android && this._android <= 2.1) { + var factor = 1 / window.devicePixelRatio; + var drawImage = CanvasRenderingContext2D.prototype.drawImage; + CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) { + if (("nodeName" in image) && /img/i.test(image.nodeName)) { + for (var i = arguments.length - 1; i >= 1; i--) { + arguments[i] = arguments[i] * factor; + } + } else if (typeof dw == "undefined") { + arguments[1] *= factor; + arguments[2] *= factor; + arguments[3] *= factor; + arguments[4] *= factor; + } + + drawImage.apply(this, arguments); + }; + } + + /** + * Check whether the user's browser supports Data URI or not + * + * @private + * @param {Function} fSuccess Occurs if it supports Data URI + * @param {Function} fFail Occurs if it doesn't support Data URI + */ + function _safeSetDataURI(fSuccess, fFail) { + var self = this; + self._fFail = fFail; + self._fSuccess = fSuccess; + + // Check it just once + if (self._bSupportDataURI === null) { + var el = document.createElement("img"); + var fOnError = function() { + self._bSupportDataURI = false; + + if (self._fFail) { + self._fFail.call(self); + } + }; + var fOnSuccess = function() { + self._bSupportDataURI = true; + + if (self._fSuccess) { + self._fSuccess.call(self); + } + }; + + el.onabort = fOnError; + el.onerror = fOnError; + el.onload = fOnSuccess; + el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data. + return; + } else if (self._bSupportDataURI === true && self._fSuccess) { + self._fSuccess.call(self); + } else if (self._bSupportDataURI === false && self._fFail) { + self._fFail.call(self); + } + }; + + /** + * Drawing QRCode by using canvas + * + * @constructor + * @param {HTMLElement} el + * @param {Object} htOption QRCode Options + */ + var Drawing = function (el, htOption) { + this._bIsPainted = false; + this._android = _getAndroid(); + + this._htOption = htOption; + this._elCanvas = document.createElement("canvas"); + this._elCanvas.width = htOption.width; + this._elCanvas.height = htOption.height; + el.appendChild(this._elCanvas); + this._el = el; + this._oContext = this._elCanvas.getContext("2d"); + this._bIsPainted = false; + this._elImage = document.createElement("img"); + this._elImage.alt = "Scan me!"; + this._elImage.style.display = "none"; + this._el.appendChild(this._elImage); + this._bSupportDataURI = null; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _elImage = this._elImage; + var _oContext = this._oContext; + var _htOption = this._htOption; + + var nCount = oQRCode.getModuleCount(); + var nWidth = _htOption.width / nCount; + var nHeight = _htOption.height / nCount; + var nRoundedWidth = Math.round(nWidth); + var nRoundedHeight = Math.round(nHeight); + + _elImage.style.display = "none"; + this.clear(); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + var bIsDark = oQRCode.isDark(row, col); + var nLeft = col * nWidth; + var nTop = row * nHeight; + _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.lineWidth = 1; + _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.fillRect(nLeft, nTop, nWidth, nHeight); + + // 안티 앨리어싱 방지 처리 + _oContext.strokeRect( + Math.floor(nLeft) + 0.5, + Math.floor(nTop) + 0.5, + nRoundedWidth, + nRoundedHeight + ); + + _oContext.strokeRect( + Math.ceil(nLeft) - 0.5, + Math.ceil(nTop) - 0.5, + nRoundedWidth, + nRoundedHeight + ); + } + } + + this._bIsPainted = true; + }; + + /** + * Make the image from Canvas if the browser supports Data URI. + */ + Drawing.prototype.makeImage = function () { + if (this._bIsPainted) { + _safeSetDataURI.call(this, _onMakeImage); + } + }; + + /** + * Return whether the QRCode is painted or not + * + * @return {Boolean} + */ + Drawing.prototype.isPainted = function () { + return this._bIsPainted; + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height); + this._bIsPainted = false; + }; + + /** + * @private + * @param {Number} nNumber + */ + Drawing.prototype.round = function (nNumber) { + if (!nNumber) { + return nNumber; + } + + return Math.floor(nNumber * 1000) / 1000; + }; + + return Drawing; + })(); + + /** + * Get the type by string length + * + * @private + * @param {String} sText + * @param {Number} nCorrectLevel + * @return {Number} type + */ + function _getTypeNumber(sText, nCorrectLevel) { + var nType = 1; + var length = _getUTF8Length(sText); + + for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { + var nLimit = 0; + + switch (nCorrectLevel) { + case QRErrorCorrectLevel.L : + nLimit = QRCodeLimitLength[i][0]; + break; + case QRErrorCorrectLevel.M : + nLimit = QRCodeLimitLength[i][1]; + break; + case QRErrorCorrectLevel.Q : + nLimit = QRCodeLimitLength[i][2]; + break; + case QRErrorCorrectLevel.H : + nLimit = QRCodeLimitLength[i][3]; + break; + } + + if (length <= nLimit) { + break; + } else { + nType++; + } + } + + if (nType > QRCodeLimitLength.length) { + throw new Error("Too long data"); + } + + return nType; + } + + function _getUTF8Length(sText) { + var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a'); + return replacedText.length + (replacedText.length != sText ? 3 : 0); + } + + /** + * @class QRCode + * @constructor + * @example + * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); + * + * @example + * var oQRCode = new QRCode("test", { + * text : "http://naver.com", + * width : 128, + * height : 128 + * }); + * + * oQRCode.clear(); // Clear the QRCode. + * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. + * + * @param {HTMLElement|String} el target element or 'id' attribute of element. + * @param {Object|String} vOption + * @param {String} vOption.text QRCode link data + * @param {Number} [vOption.width=256] + * @param {Number} [vOption.height=256] + * @param {String} [vOption.colorDark="#000000"] + * @param {String} [vOption.colorLight="#ffffff"] + * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] + */ + QRCode = function (el, vOption) { + this._htOption = { + width : 256, + height : 256, + typeNumber : 4, + colorDark : "#000000", + colorLight : "#ffffff", + correctLevel : QRErrorCorrectLevel.H + }; + + if (typeof vOption === 'string') { + vOption = { + text : vOption + }; + } + + // Overwrites options + if (vOption) { + for (var i in vOption) { + this._htOption[i] = vOption[i]; + } + } + + if (typeof el == "string") { + el = document.getElementById(el); + } + + if (this._htOption.useSVG) { + Drawing = svgDrawer; + } + + this._android = _getAndroid(); + this._el = el; + this._oQRCode = null; + this._oDrawing = new Drawing(this._el, this._htOption); + + if (this._htOption.text) { + this.makeCode(this._htOption.text); + } + }; + + /** + * Make the QRCode + * + * @param {String} sText link data + */ + QRCode.prototype.makeCode = function (sText) { + this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel); + this._oQRCode.addData(sText); + this._oQRCode.make(); + this._el.title = sText; + this._oDrawing.draw(this._oQRCode); + this.makeImage(); + }; + + /** + * Make the Image from Canvas element + * - It occurs automatically + * - Android below 3 doesn't support Data-URI spec. + * + * @private + */ + QRCode.prototype.makeImage = function () { + if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) { + this._oDrawing.makeImage(); + } + }; + + /** + * Clear the QRCode + */ + QRCode.prototype.clear = function () { + this._oDrawing.clear(); + }; + + /** + * @name QRCode.CorrectLevel + */ + QRCode.CorrectLevel = QRErrorCorrectLevel; +})(); diff --git a/app/assets/javascripts/qrcode.js.coffee b/app/assets/javascripts/qrcode_op.js.coffee similarity index 57% rename from app/assets/javascripts/qrcode.js.coffee rename to app/assets/javascripts/qrcode_op.js.coffee index f049ae8..be42a49 100644 --- a/app/assets/javascripts/qrcode.js.coffee +++ b/app/assets/javascripts/qrcode_op.js.coffee @@ -1,4 +1,6 @@ $(document).on 'turbolinks:load', -> + if $('#image-tag').length > 0 + new QRCode( $('#image-tag')[0], $('#image-tag').data('url') ) $('#qrcode-link').click (event)-> event.preventDefault() $('.social-share').toggle() diff --git a/app/assets/stylesheets/comments.scss b/app/assets/stylesheets/comments.scss index 686ab41..5e79a2b 100644 --- a/app/assets/stylesheets/comments.scss +++ b/app/assets/stylesheets/comments.scss @@ -1,3 +1,7 @@ +#alert-container { + display: none; +} + .comment-field { background-color: #333333; padding-top: 3rem; @@ -79,7 +83,7 @@ &:hover { background-color: #444444; } - + .name { color: #DDDDDD; } @@ -90,5 +94,5 @@ white-space: pre-wrap; word-break: break-all; } - + } diff --git a/app/assets/stylesheets/qrcodes.scss b/app/assets/stylesheets/qrcodes.scss index d8f6cba..d2f81b0 100644 --- a/app/assets/stylesheets/qrcodes.scss +++ b/app/assets/stylesheets/qrcodes.scss @@ -1,20 +1,4 @@ -.qrcode-image { - table { - border-width: 0; - border-style: none; - border-color: #0000ff; - border-collapse: collapse; - } - td { - border-width: 0; - border-style: none; - border-color: #0000ff; - border-collapse: collapse; - padding: 0; - margin: 0; - width: 0.3rem; - height: 0.3rem; - } - td.black { background-color: #000; } - td.white { background-color: #fff; } +#image-tag { + float: right; + width: 200px; } diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb index 67db492..403a7b8 100644 --- a/app/controllers/blogs_controller.rb +++ b/app/controllers/blogs_controller.rb @@ -21,7 +21,7 @@ class BlogsController < ApplicationController @post.visited @prev = Post.where('created_at < ?', @post.created_at).order(created_at: :desc).first @prev = Post.where('created_at > ?', @post.created_at).order(created_at: :asc).first - @comments = @post.comments + @comments = @post.comments.order(created_at: :desc) @likes_count = @post.likes.count respond_to do |format| format.html diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 00bc13b..cfba707 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -8,19 +8,22 @@ class CommentsController < ApplicationController end def create + cookies[:name] = comment_params[:name] + cookies[:email] = comment_params[:email] @post = Post.find( params[:blog_id] ) - comment = @post.comments.build(comment_params) + @comment = @post.comments.build(comment_params) - if comment.save - render :json=> { success: true, data: build_json(comment) } + if @comment.save + @comments = @post.comments.order(created_at: :desc) + render :create_ok else - render :json=> { success: false, message: comment.errors.full_messages.join(", ") } + render :create_fail end end private def comment_params - params.permit(:content, :name, :email) + params.require(:comment).permit(:content, :name, :email) end def build_json(comment) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ae257cc..6d7c9dd 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,5 +1,3 @@ module ApplicationHelper - def format_date(time) - time.strftime('%Y-%m-%d') - end + # some format function is defined in app/controllers/application_controller.rb end diff --git a/app/views/blogs/_comment.html.slim b/app/views/blogs/_comment.html.slim index 74b0e69..e26462b 100644 --- a/app/views/blogs/_comment.html.slim +++ b/app/views/blogs/_comment.html.slim @@ -1,22 +1,16 @@ .row .small-12.large-9.large-centered.columns - form novalidate='' name='form' - = form_for Comment.new, url: blog_comments_path(@post) do |f| + = form_for Comment.new, url: blog_comments_path(@post), remote: true do |f| .row .small-12.large-12.columns = f.text_area :content, placeholder: t('comment_placeholder.content') .row .small-12.large-6.columns - = f.text_field :name, placeholder: t('comment_placeholder.name') - = f.text_field :email, placeholder: t('comment_placeholder.email') - button.button.comment-submit type='submit' #{t('comment_placeholder.submit')} - .comment-diag - .comment-wrapper - - comments.each do |comment| - p.name - | #{comment.name} - | " • " - span.created-at - | #{comment.created_at } - / ignore "white-space: pre" 's effect -

#{comment.content}

+ = f.text_field :name, value: cookies[:name], placeholder: t('comment_placeholder.name') + = f.text_field :email, value: cookies[:email], placeholder: t('comment_placeholder.email') + button.button.comment-submit type='submit' data-disable-with=t('comment_placeholder.submitting') #{t('comment_placeholder.submit')} + #alert-container.alert.callout + span.text + button class="close-button" type='button' + span × + = render partial: 'comments/comment_content', locals: { comments: comments } diff --git a/app/views/blogs/_qrcode.html.slim b/app/views/blogs/_qrcode.html.slim index f5203c2..abb43aa 100644 --- a/app/views/blogs/_qrcode.html.slim +++ b/app/views/blogs/_qrcode.html.slim @@ -1,3 +1,3 @@ .qrcode-image - = image_tag( qrcodes_path(str: str) ) + #image-tag data-url=str p #{t('qrcodetips')} diff --git a/app/views/blogs/show.html.slim b/app/views/blogs/show.html.slim index 8537bb8..0944887 100644 --- a/app/views/blogs/show.html.slim +++ b/app/views/blogs/show.html.slim @@ -1,12 +1,12 @@ - content_for(:meta) do - meta name="description" content="#{@post.meta_content}" + meta name="description" content=@post.meta_content meta name="keywords" content=@post.labels_content - content_for(:title) do | #{@post.title} .row.blog-wrapper .small-12.large-9.large-centered.columns - = render partial: "post", :locals=> { :post=> @post } + = render partial: "post", :locals=> { post: @post } .comment-field = render partial: 'comment', locals: { comments: @comments, post: @post } .row diff --git a/app/views/comments/_comment_content.html.slim b/app/views/comments/_comment_content.html.slim new file mode 100644 index 0000000..389fa54 --- /dev/null +++ b/app/views/comments/_comment_content.html.slim @@ -0,0 +1,10 @@ +.comment-diag + - comments.each do |comment| + .comment-wrapper + p.name + | #{comment.name} + | #{" • "} + span.created-at + | #{format_time(comment.created_at) } + / ignore "white-space: pre" 's effect +

#{comment.content}

diff --git a/app/views/comments/create_fail.js.erb b/app/views/comments/create_fail.js.erb new file mode 100644 index 0000000..bd38c84 --- /dev/null +++ b/app/views/comments/create_fail.js.erb @@ -0,0 +1,2 @@ +$('#alert-container .text').text(' <%= @comment.errors.full_messages.join(' ') %>' ); +$('#alert-container').removeClass('success').addClass('alert').show(); diff --git a/app/views/comments/create_ok.js.erb b/app/views/comments/create_ok.js.erb new file mode 100644 index 0000000..d7eb497 --- /dev/null +++ b/app/views/comments/create_ok.js.erb @@ -0,0 +1,4 @@ +$('#comment_content').val(''); +$('#alert-container .text').text(' <%= t('comment_placeholder.publish_success') %>' ); +$('#alert-container').removeClass('alert').addClass('success').show(); +$('.comment-diag').replaceWith('<%= j render partial: 'comment_content', locals: { comments: @comments }%>'); diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 54d6c5e..822db90 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -44,7 +44,7 @@ zh-CN: comment_placeholder: content: '发表你的评论...' name: '名字' - email: '邮箱' + email: '邮箱, your@example.com' submit: '提交' submitting: '提交中' publish_success: '发表成功' From 033339182b2cab4661b0348998bb9d7e266c2840 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Sun, 24 Apr 2016 00:43:05 +0800 Subject: [PATCH 10/14] Adjust comment and qrcode feature --- app/assets/javascripts/qrcode_op.js.coffee | 7 +++++++ app/assets/stylesheets/blogs.scss | 12 ++++++++---- app/assets/stylesheets/comments.scss | 12 +++++++----- app/assets/stylesheets/qrcodes.scss | 1 + app/controllers/blogs_controller.rb | 2 +- app/views/admin/comments/index.html.slim | 2 +- app/views/blogs/index.html.slim | 17 ++++------------- app/views/blogs/show.html.slim | 1 + app/views/comments/_comment_content.html.slim | 3 +-- app/views/comments/_comment_pre.html.slim | 2 ++ 10 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 app/views/comments/_comment_pre.html.slim diff --git a/app/assets/javascripts/qrcode_op.js.coffee b/app/assets/javascripts/qrcode_op.js.coffee index be42a49..3596dff 100644 --- a/app/assets/javascripts/qrcode_op.js.coffee +++ b/app/assets/javascripts/qrcode_op.js.coffee @@ -1,6 +1,13 @@ $(document).on 'turbolinks:load', -> + + if $('#qrcode-home').length > 0 + $('#qrcode-home').empty() + new QRCode( $('#qrcode-home')[0], $('#qrcode-home').data('url') ) + if $('#image-tag').length > 0 + $('#image-tag').empty() new QRCode( $('#image-tag')[0], $('#image-tag').data('url') ) + $('#qrcode-link').click (event)-> event.preventDefault() $('.social-share').toggle() diff --git a/app/assets/stylesheets/blogs.scss b/app/assets/stylesheets/blogs.scss index 0b86b25..e890c20 100644 --- a/app/assets/stylesheets/blogs.scss +++ b/app/assets/stylesheets/blogs.scss @@ -60,6 +60,10 @@ padding-left: 0rem; } +#qrcode-home { + padding: 1rem 2rem 1rem 0; +} + .qrcode { display: inline-block; float: right; @@ -69,10 +73,6 @@ } } -.social-share { - display: none; -} - .qrcode-wrapper { float: right; margin-top: -2rem; @@ -85,6 +85,10 @@ } } +.social-share { + display: none; +} + .subscribe-ul { list-style-type: none; margin-left: 0; diff --git a/app/assets/stylesheets/comments.scss b/app/assets/stylesheets/comments.scss index 5e79a2b..5d3d84b 100644 --- a/app/assets/stylesheets/comments.scss +++ b/app/assets/stylesheets/comments.scss @@ -47,14 +47,17 @@ color: #b3b3b3; } .comment-content { - padding-bottom: 2.275rem; + padding-bottom: 1rem; padding-left: 0.275rem; border-bottom: 1px dashed #8a8a8a; margin-bottom: 0; - white-space: pre; + + p { + margin-bottom: 0.325rem; + } } .name { - padding-top: 0.5rem; + padding-top: 1rem; padding-left: 0.275rem; } } @@ -79,7 +82,7 @@ } .comment-wrapper { - margin-bottom: 0.5rem; + &:hover { background-color: #444444; } @@ -91,7 +94,6 @@ .comment-content { word-wrap: break-word; color: #DDDDDD; - white-space: pre-wrap; word-break: break-all; } diff --git a/app/assets/stylesheets/qrcodes.scss b/app/assets/stylesheets/qrcodes.scss index d2f81b0..339ae61 100644 --- a/app/assets/stylesheets/qrcodes.scss +++ b/app/assets/stylesheets/qrcodes.scss @@ -1,4 +1,5 @@ #image-tag { float: right; width: 200px; + margin-bottom: 1rem; } diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb index 403a7b8..93a1e23 100644 --- a/app/controllers/blogs_controller.rb +++ b/app/controllers/blogs_controller.rb @@ -20,7 +20,7 @@ class BlogsController < ApplicationController @post = Post.find(params[:id]) @post.visited @prev = Post.where('created_at < ?', @post.created_at).order(created_at: :desc).first - @prev = Post.where('created_at > ?', @post.created_at).order(created_at: :asc).first + @next = Post.where('created_at > ?', @post.created_at).order(created_at: :asc).first @comments = @post.comments.order(created_at: :desc) @likes_count = @post.likes.count respond_to do |format| diff --git a/app/views/admin/comments/index.html.slim b/app/views/admin/comments/index.html.slim index 4dc9142..9c17013 100644 --- a/app/views/admin/comments/index.html.slim +++ b/app/views/admin/comments/index.html.slim @@ -18,7 +18,7 @@ td = mail_to comment.email td - p.pre #{comment.content} + = simple_format(comment.content) td = format_time(comment.created_at) diff --git a/app/views/blogs/index.html.slim b/app/views/blogs/index.html.slim index 5ce915e..b58bbe4 100644 --- a/app/views/blogs/index.html.slim +++ b/app/views/blogs/index.html.slim @@ -27,20 +27,11 @@ .row.ng-cloak ng-controller='AboutController' .small-12.medium-6.large-12.columns ul.subscribe-ul - - if ENV['MAIL_SERVER'].present? - li - = link_to t('subscribes.email'), '', "ng-click"=>"click('email')" - .email-subscribe ng-show="type == 'email'" - = text_field_tag 'email', nil, placeholder: 'your@email.com', 'ng-model'=>'email' - button.small ng-click="subscribe()" ng-disabled="! email_validate()" #{t('subscribes.submit')} - span.subscribe-success ng-show="subscribe_success" #{t('subscribes.submit_success')} - span.subscribe-fail ng-show="subscribe_success == false" {{subscribe_fail_msg}} li - = link_to t('subscribes.wechat'), '', "ng-click"=>"click('weixin')" - .weixin-subscribe ng-show="type == 'weixin'" - = render partial: "qrcode", locals: { str: root_url } + a data-toggle="qrcode-home" #{t('subscribes.wechat') } + #qrcode-home.weixin-subscribe.hide data-toggler='hide' data-url=root_url li - = link_to t('subscribes.rss'), '', "ng-click"=>"click('rss')" - .rss-subscribe ng-show="type == 'rss'" + a data-toggle="rss-home" #{t('subscribes.rss') } + #rss-home.rss-subscribe.hide data-toggler='hide' = link_to rss_blogs_path do - image_tag('rss.png') diff --git a/app/views/blogs/show.html.slim b/app/views/blogs/show.html.slim index 0944887..9bda14d 100644 --- a/app/views/blogs/show.html.slim +++ b/app/views/blogs/show.html.slim @@ -9,6 +9,7 @@ = render partial: "post", :locals=> { post: @post } .comment-field = render partial: 'comment', locals: { comments: @comments, post: @post } + p .row .small-12.large-9.large-centered.columns - if @prev diff --git a/app/views/comments/_comment_content.html.slim b/app/views/comments/_comment_content.html.slim index 389fa54..4979940 100644 --- a/app/views/comments/_comment_content.html.slim +++ b/app/views/comments/_comment_content.html.slim @@ -6,5 +6,4 @@ | #{" • "} span.created-at | #{format_time(comment.created_at) } - / ignore "white-space: pre" 's effect -

#{comment.content}

+ = render partial: 'comments/comment_pre', locals: { comment: comment } diff --git a/app/views/comments/_comment_pre.html.slim b/app/views/comments/_comment_pre.html.slim new file mode 100644 index 0000000..fc2ebe5 --- /dev/null +++ b/app/views/comments/_comment_pre.html.slim @@ -0,0 +1,2 @@ +.comment-content + = simple_format(comment.content) From e0346dca01d6bc88228804e72f245a1ae0026669 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Sun, 24 Apr 2016 15:22:24 +0800 Subject: [PATCH 11/14] Deploy --- Gemfile | 2 +- Gemfile.lock | 6 ++++-- config/deploy.rb | 16 +++++++++------- config/deploy/zh.rb | 3 +-- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 02e6225..c04b2e4 100644 --- a/Gemfile +++ b/Gemfile @@ -41,7 +41,7 @@ gem 'puma' gem 'mina', require: false gem 'mina-multistage', require: false gem 'mina-sidekiq', require: false -gem 'mina-unicorn', require: false +gem 'mina-puma', require: false group :development do gem 'quiet_assets' diff --git a/Gemfile.lock b/Gemfile.lock index ffc774e..c3c5998 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -152,9 +152,11 @@ GEM rake mina-multistage (1.0.2) mina (>= 0.2.1) + mina-puma (0.3.0) + mina + puma (>= 2.13) mina-sidekiq (0.3.1) mina - mina-unicorn (0.4.0) mini_magick (4.5.1) mini_portile2 (2.0.0) minitest (5.8.4) @@ -345,8 +347,8 @@ DEPENDENCIES listen (~> 3.0.5) mina mina-multistage + mina-puma mina-sidekiq - mina-unicorn mini_magick newrelic_rpm nokogiri diff --git a/config/deploy.rb b/config/deploy.rb index 80a7ace..a04f3d4 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -5,17 +5,19 @@ require 'mina/multistage' require 'mina/bundler' require 'mina/rails' require 'mina/git' -require 'mina/rvm' # for rvm support. (http://rvm.io) -require 'mina/unicorn' +require 'mina/rvm' +require 'mina/puma' require 'mina_sidekiq/tasks' # Manually create these paths in shared/ (eg: shared/config/database.yml) in your server. # They will be linked in the 'deploy:link_shared_paths' step. -set :shared_paths, ['config/mongoid.yml', 'config/application.yml', 'log', 'tmp', 'public/uploads', 'public/personal' ] +set :shared_paths, ['config/database.yml', 'config/application.yml', 'log', 'tmp', 'public/uploads', 'public/personal' ] + +# rvm path +set :rvm_path, '/usr/local/rvm/scripts/rvm' task :environment do - queue! %[source /usr/local/rvm/scripts/rvm] - queue! %[rvm use 2.0.0] + invoke :'rvm:use[2.2.3]' end task :setup => :environment do @@ -24,7 +26,7 @@ task :setup => :environment do queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/#{dir}"] end - ['config/mongoid.yml', 'config/application.yml'].each do |file| + ['config/database.yml', 'config/application.yml'].each do |file| queue! %[touch "#{deploy_to}/shared/#{file}"] queue %[echo "-----> Be sure to edit 'shared/#{file}'."] end @@ -47,7 +49,7 @@ task :deploy => :environment do invoke :'rails:assets_precompile' to :launch do - invoke :'unicorn:restart' + invoke :'puma:restart' invoke :'sidekiq:restart' end end diff --git a/config/deploy/zh.rb b/config/deploy/zh.rb index f568d5f..dbd7fcc 100644 --- a/config/deploy/zh.rb +++ b/config/deploy/zh.rb @@ -1,6 +1,5 @@ set :domain, 'yafeilee.me' set :deploy_to, '/home/ruby/wblog' set :repository, 'git@github.com:windy/wblog.git' -set :branch, 'master' +set :branch, 'new_design' set :user, 'ruby' -set :unicorn_config, -> { "#{deploy_to}/#{current_path}/config/unicorn/zh.rb" } From dee8533df94cf4a6258936d2f55f79309aa48d08 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Sun, 24 Apr 2016 15:58:24 +0800 Subject: [PATCH 12/14] Deploy file update --- config/deploy.rb | 2 ++ config/environments/production.rb | 2 +- config/puma.rb | 8 -------- 3 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 config/puma.rb diff --git a/config/deploy.rb b/config/deploy.rb index a04f3d4..5706a71 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -52,5 +52,7 @@ task :deploy => :environment do invoke :'puma:restart' invoke :'sidekiq:restart' end + + invoke :'deploy:cleanup' end end diff --git a/config/environments/production.rb b/config/environments/production.rb index d5627a4..979f3ee 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -20,7 +20,7 @@ WBlog::Application.configure do # config.action_dispatch.rack_cache = true # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_files = false + config.public_file_server.enabled = false # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier diff --git a/config/puma.rb b/config/puma.rb deleted file mode 100644 index 604e784..0000000 --- a/config/puma.rb +++ /dev/null @@ -1,8 +0,0 @@ -threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i -threads threads_count, threads_count - -port ENV.fetch("PORT") { 3000 } - -environment ENV.fetch("RAILS_ENV") { "development" } - -plugin :tmp_restart From c041191aea13e6ce97c1fbea321e2d2f9c0c2cdc Mon Sep 17 00:00:00 2001 From: yafeilee Date: Sun, 24 Apr 2016 17:04:17 +0800 Subject: [PATCH 13/14] deploy file update --- config/deploy.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/deploy.rb b/config/deploy.rb index 5706a71..6082d3f 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -49,7 +49,9 @@ task :deploy => :environment do invoke :'rails:assets_precompile' to :launch do - invoke :'puma:restart' + # Insure puma is start when restart it + invoke :'puma:start' + invoke :'puma:phased_restart' invoke :'sidekiq:restart' end From 86fdce2b43c92eb416988ae998286cd7aba2db42 Mon Sep 17 00:00:00 2001 From: yafeilee Date: Sun, 24 Apr 2016 23:51:39 +0800 Subject: [PATCH 14/14] English deploy file --- config/deploy/en.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/deploy/en.rb b/config/deploy/en.rb index f53c0ad..b301ef4 100644 --- a/config/deploy/en.rb +++ b/config/deploy/en.rb @@ -1,6 +1,5 @@ set :domain, 'yafeilee.me' set :deploy_to, '/home/ruby/wblog_en' set :repository, 'git@github.com:windy/wblog.git' -set :branch, 'master' +set :branch, 'new_design' set :user, 'ruby' -set :unicorn_config, -> { "#{deploy_to}/#{current_path}/config/unicorn/en.rb" }