diff --git a/Gemfile b/Gemfile index 03c7d1d..23665d4 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,7 @@ gem 'active_model_serializers' gem 'active_api', github: 'blairanderson/active_api' # gem 'active_api', path: '../active_api' +gem 'bootstrap-sass', '~> 3.3.3' gem 'jquery-rails' gem 'pg' gem 'rails', '4.2.0' @@ -16,6 +17,11 @@ gem 'turbolinks' gem 'uglifier', '>= 1.3.0' gem 'validate_url' +# This allows us to import bower packages +source 'https://rails-assets.org' do + gem 'rails-assets-bootstrap-material-design' +end + group :production do gem 'rails_12factor' end @@ -31,6 +37,7 @@ group :development, :test do gem 'factory_girl_rails' gem 'faker' + gem 'pry' gem 'rspec-rails', '~> 3.0' # https://github.com/rspec/rspec-rails gem 'rspec_api_documentation' # https://github.com/zipmark/rspec_api_documentation gem 'shoulda-matchers' diff --git a/Gemfile.lock b/Gemfile.lock index d784f39..90cd560 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: git://github.com/blairanderson/active_api.git - revision: 3a842f983dcb01e6f2e84e5924c5f7f014732290 + revision: 37b285bb3d4ba03d907e4b69474fe98d51ab4adb specs: active_api (0.0.1) active_model_serializers @@ -10,6 +10,7 @@ GIT GEM remote: https://rubygems.org/ + remote: https://rails-assets.org/ specs: actionmailer (4.2.0) actionpack (= 4.2.0) @@ -50,6 +51,9 @@ GEM tzinfo (~> 1.1) addressable (2.3.7) arel (6.0.0) + autoprefixer-rails (5.1.7) + execjs + json axiom-types (0.1.1) descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) @@ -57,11 +61,15 @@ GEM bcrypt (3.1.10) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) + bootstrap-sass (3.3.3) + autoprefixer-rails (>= 5.0.0.1) + sass (>= 3.2.19) builder (3.2.2) byebug (3.5.1) columnize (~> 0.8) debugger-linecache (~> 1.2) slop (~> 3.6) + coderay (1.1.0) coercible (1.0.0) descendants_tracker (~> 0.0.1) coffee-rails (4.1.0) @@ -124,6 +132,7 @@ GEM nokogiri (>= 1.5.9) mail (2.6.3) mime-types (>= 1.16, < 3) + method_source (0.8.2) mime-types (2.4.3) mini_portile (0.6.2) minitest (5.5.1) @@ -141,6 +150,10 @@ GEM multi_xml (~> 0.5) rack (~> 1.2) pg (0.18.1) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) rack (1.6.0) rack-accept (0.4.5) rack (>= 0.4) @@ -159,6 +172,9 @@ GEM bundler (>= 1.3.0, < 2.0) railties (= 4.2.0) sprockets-rails + rails-assets-bootstrap-material-design (0.2.2) + rails-assets-jquery (~> 2.1.1) + rails-assets-jquery (2.1.3) rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) rails-dom-testing (1.0.5) @@ -261,12 +277,15 @@ PLATFORMS DEPENDENCIES active_api! active_model_serializers + bootstrap-sass (~> 3.3.3) byebug factory_girl_rails faker jquery-rails pg + pry rails (= 4.2.0) + rails-assets-bootstrap-material-design! rails_12factor rspec-rails (~> 3.0) rspec_api_documentation diff --git a/app/assets/javascripts/admin/root.js b/app/assets/javascripts/admin/root.js index b1db29c..300a4d0 100644 --- a/app/assets/javascripts/admin/root.js +++ b/app/assets/javascripts/admin/root.js @@ -1,42 +1,57 @@ -var ready = function() { - $('#reset-and-load-from-hn').click(function(e) { +function fetchStory(id, callback) { + $.getJSON('https://hacker-news.firebaseio.com/v0/item/' + id + '.json?print=pretty', function(story, status, jqxhr) { + if (status === "error") { + return callback(status) + } else { + if (story.text) { + story.content = story.text; + } + + callback(null, { + item: story, + status: status + }); + } + }); +} + + +ready(function() { + $(document).on('click', '#reset-and-load-from-hn', function(e) { var apiRoot = $(this).data('api'); // use API to fetch all items. // use api to destroy all items? - debugger - //https://github.com/HackerNews/API // use api to fetch the top hackernews stories. - $.getJSON("https://hacker-news.firebaseio.com/v0/topstories.json", function(stories, status, jqxhr){ - debugger - stories.forEach(function(story) { - var data = { - title: story.title - }; - - if (story.url){ - data.url = story.url; - } - if (story.content){ - data.content = story.content; - } - - $.ajax({ - type: "POST", - url: apiRoot+"/items", - data: data, - success: function(e){ + $.getJSON("https://hacker-news.firebaseio.com/v0/topstories.json", function(stories, status, jqxhr) { + + stories.forEach(function(story_id) { + fetchStory(story_id, function(error, result) { + if (error || !result.item ) { + console.log('rawr', error, result); + return + } + + $.ajax({ + type: "POST", + url: apiRoot + "/items", + data: result, + dataType: "JSON", + headers: { + "Authorization": "Token token="+window.current_user.token + } + }).success(function(e) { + debugger + + }).error(function(e) { debugger - }, - dataType: "JSON" + }); + }); }) }); // use api to add all the hackernews stories }) -}; - -$(document).ready(ready); -$(document).on('page:load', ready); +}) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 4605d37..77632d2 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,5 +12,8 @@ // //= require jquery //= require jquery_ujs +//= require ready //= require turbolinks -//= require admin/root +//= require bootstrap +//= require bootstrap-material-design +//= require vendor/bootstrap_material_design_config diff --git a/app/assets/javascripts/ready.js b/app/assets/javascripts/ready.js new file mode 100644 index 0000000..00649c3 --- /dev/null +++ b/app/assets/javascripts/ready.js @@ -0,0 +1,6 @@ +function ready(callback) { + $(document).ready(callback); + $(document).on('page:load', callback); +} + +window.ready = ready; diff --git a/app/assets/javascripts/vendor/bootstrap_material_design_config.js b/app/assets/javascripts/vendor/bootstrap_material_design_config.js new file mode 100644 index 0000000..c19b737 --- /dev/null +++ b/app/assets/javascripts/vendor/bootstrap_material_design_config.js @@ -0,0 +1,3 @@ +ready(function() { + $.material.init() +}) diff --git a/app/assets/javascripts/vendor/theme.js b/app/assets/javascripts/vendor/theme.js new file mode 100644 index 0000000..7148d5a --- /dev/null +++ b/app/assets/javascripts/vendor/theme.js @@ -0,0 +1,77 @@ +ready(function() { + var $container = $('.portfolio'), + $items = $container.find('.portfolio-item'), + portfolioLayout = 'fitRows'; + + if ($container.hasClass('portfolio-centered')) { + portfolioLayout = 'masonry'; + } + + $container.isotope({ + filter: '*', + animationEngine: 'best-available', + layoutMode: portfolioLayout, + animationOptions: { + duration: 750, + easing: 'linear', + queue: false + }, + masonry: {} + }, refreshWaypoints()); + + function refreshWaypoints() { + setTimeout(function() { + }, 1000); + } + + $('nav.portfolio-filter ul a').on('click', function() { + var selector = $(this).attr('data-filter'); + $container.isotope({filter: selector}, refreshWaypoints()); + $('nav.portfolio-filter ul a').removeClass('active'); + $(this).addClass('active'); + return false; + }); + + function getColumnNumber() { + var winWidth = $(window).width(), + columnNumber = 1; + + if (winWidth > 1200) { + columnNumber = 5; + } else if (winWidth > 950) { + columnNumber = 4; + } else if (winWidth > 600) { + columnNumber = 3; + } else if (winWidth > 400) { + columnNumber = 2; + } else if (winWidth > 250) { + columnNumber = 1; + } + return columnNumber; + } + + function setColumns() { + var winWidth = $(window).width(), + columnNumber = getColumnNumber(), + itemWidth = Math.floor(winWidth / columnNumber); + + $container.find('.portfolio-item').each(function() { + $(this).css({ + width: itemWidth + 'px' + }); + }); + } + + function setPortfolio() { + setColumns(); + $container.isotope('reLayout'); + } + + $container.imagesLoaded(function() { + setPortfolio(); + }); + + $(window).on('resize', function() { + setPortfolio(); + }); +}); diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.scss similarity index 86% rename from app/assets/stylesheets/application.css rename to app/assets/stylesheets/application.scss index f9cd5b3..16b967b 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.scss @@ -10,6 +10,9 @@ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * - *= require_tree . - *= require_self + *= bootstrap-material-design */ + +@import "bootstrap_and_overrides"; +@import "theme"; +@import "items"; diff --git a/app/assets/stylesheets/bootstrap_and_overrides.scss b/app/assets/stylesheets/bootstrap_and_overrides.scss new file mode 100644 index 0000000..baccee2 --- /dev/null +++ b/app/assets/stylesheets/bootstrap_and_overrides.scss @@ -0,0 +1,2 @@ +@import "bootstrap-sprockets"; +@import "bootstrap"; diff --git a/app/assets/stylesheets/components/navigation.scss b/app/assets/stylesheets/components/navigation.scss index 22d27bd..e69de29 100644 --- a/app/assets/stylesheets/components/navigation.scss +++ b/app/assets/stylesheets/components/navigation.scss @@ -1,15 +0,0 @@ -@mixin clearfix() { - &:before, - &:after { - content: " "; // 1 - display: table; // 2 - } - &:after { - clear: both; - } -} - - -.row { - @include clearfix(); -} diff --git a/app/assets/stylesheets/theme.scss b/app/assets/stylesheets/theme.scss new file mode 100755 index 0000000..6417f8e --- /dev/null +++ b/app/assets/stylesheets/theme.scss @@ -0,0 +1,458 @@ +/* ################################################################ + + Author: Carlos Alvarez + URL: http://alvarez.is + + Project Name: SOLID - Bootstrap 3 Theme + Version: 1.0 + URL: http://alvarez.is + +################################################################# */ +@import url(http://fonts.googleapis.com/css?family=Raleway:400,700,900); +@import url(http://fonts.googleapis.com/css?family=Lato:400,900); +//@import url("prettyPhoto.css") screen; +//@import url("hoverex-all.css") screen; + +/* ################################################################ + 1. GENERAL STRUCTURES +################################################################# */ + * { + margin: 0; + padding: 0px; + } + +body { + background: #ffffff; + margin: 0; + height: 100%; + color: #384452; + font-family: 'Lato', sans-serif; + font-weight: 400; + } + +h1, h2, h3, h4, h5, h6 { + font-family: 'Raleway', sans-serif; + font-weight: 700; +} + +p { + padding: 0; + margin-bottom: 12px; + font-family: 'Lato', sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 24px; + color: #384452; + margin-top: 10px; +} + +img { + height: auto; + max-width: 100%; +} + +a { + padding: 0; + margin: 0; + text-decoration: none; + -webkit-transition: background-color .4s linear, color .4s linear; + -moz-transition: background-color .4s linear, color .4s linear; + -o-transition: background-color .4s linear, color .4s linear; + -ms-transition: background-color .4s linear, color .4s linear; + transition: background-color .4s linear, color .4s linear; +} +a:hover, +a:focus { + text-decoration: none; + color:#01b2fe; +} + +::-moz-selection { + color: #fff; + text-shadow:none; + background:#2B2E31; +} +::selection { + color: #fff; + text-shadow:none; + background:#2B2E31; +} + +.centered { + text-align: center +} + +/* ################################################################ + BOOTSTRAP MODIFICATIONS & TWEAKS +################################################################# */ +.navbar { + min-height: 70px; + padding-top: 10px; + margin-bottom: 0px; +} + +.navbar-brand { + font-family: 'Raleway', sans-serif; + font-weight: 900; +} + +.navbar-header .navbar-brand { + color: white; +} + +.navbar-default .navbar-nav > li > a { + color: white; + font-weight: 700; + font-size: 12px; +} + +.navbar-default .navbar-nav > li > a:hover { + color: #00b3fe; +} + +.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { + color: #00b3fe; + background-color: transparent; +} + +.navbar-default { + background-color: #384452; + border-color: transparent; +} + +.dropdown-menu { + background: #384452; +} + +.dropdown-menu > li > a { + color: white; + font-weight: 700; + font-size: 12px; +} + +.btn-theme { + color: #fff; + background-color: #384452; + border-color: #384452; + margin: 4px; +} +.btn-theme:hover, +.btn-theme:focus, +.btn-theme:active, +.btn-theme.active, +.open .dropdown-toggle.btn-theme { + color: #fff; + background-color: #00b3fe; + border-color: #00b3fe; +} + +.dmbutton:hover, +.dmbutton:active, +.dmbutton:focus{ + color: #ffffff; + background-color: #222222; + border-color: #ffffff; +} +.dmbutton { + background:rgba(0, 0, 0, 0); + border: 1px solid #ffffff; + color: #ffffff; + -webkit-border-radius: 2px; + border-radius: 2px; + padding-top: 1.025rem; + padding-right: 2.25rem; + letter-spacing:0.85px; + padding-bottom: 1.0875rem; + padding-left: 2.25rem; + font-size: 1.55rem; + cursor: pointer; + font-weight: normal; + line-height: normal; + margin: 0 0 1.25rem; + text-decoration: none; + text-align: center; + display: inline-block; + -webkit-transition: background-color 300ms ease-out; + -moz-transition: background-color 300ms ease-out; + transition: background-color 300ms ease-out; + -webkit-appearance: none; + font-weight: normal !important; +} + +.mtb { + margin-top: 80px; + margin-bottom: 80px; +} + +.mb { + margin-bottom: 60px; +} + +.mt { + margin-top: 60px; +} + +.hline { + border-bottom: 2px solid #384452; +} + +.hline-w { + border-bottom: 2px solid #ffffff; + margin-bottom: 25px; +} +/* ################################################################ + SITE WRAPS +################################################################# */ + +#headerwrap { + background-color: #00b3fe; +// min-height: 550px; +// padding-top: 100px; + padding-bottom: 0px; + text-align: center; +} + +#headerwrap h3, h5 { + color: white; + font-weight: 400; +} + +#headerwrap h1 { + color: white; + margin-bottom: 25px; +} + +#headerwrap .img-responsive { + margin: 0 auto; +} + +/* Services Wrap */ +#service { + margin-top: 40px; + margin-bottom: 80px; +} + +#service i { + color: #00b3fe; + font-size: 60px; + padding: 15px; +} + +/* Portfolio Wrap */ +#portfoliowrap { + padding-top: 60px; + margin-bottom: 60px; + display: block; + text-align: center +} + +#portfoliowrap h3 { + margin-bottom: 25px; +} + +.portfolio { + padding:0 !important; + margin:0 !important; + display:block; +} + + +.portfolio-item .title:before {border-radius:0; display:none} +.portfolio-item p {margin:0px 0 30px;} +.portfolio-item h3 {margin:-10px 0 10px; font-size:16px; text-transform:uppercase;} + + +.tpl6 h3 { + color:#fff; + margin:0; + padding:40px 5px 0; + font-size:16px; + text-transform:uppercase; +} +.tpl6 .dmbutton { + display:inline-block; + margin:30px 5px 20px 5px; + font-size:13px; +} + +.tpl6 .bg +{ + height:100%; + width:100%; + background-color:#00b3fe; + background-color:rgba(0,179,254,.9); + text-align:center; +} + +/* Testimonials Wrap */ +#twrap { + background: url(../img/t-back.jpg) no-repeat center top; + margin-top: 0px; + padding-top:60px; + text-align:center; + background-attachment: relative; + background-position: center center; + min-height: 450px; + width: 100%; + + -webkit-background-size: 100%; + -moz-background-size: 100%; + -o-background-size: 100%; + background-size: 100%; + + -webkit-background-size: cover; + -moz-background-size: cover; + -o-background-size: cover; + background-size: cover; +} + +#twrap i { + font-size: 50px; + color: white; + margin-bottom: 25px; +} + +#twrap p { + color: white; + font-size: 15px; + line-height: 30px; +} + +/* clients logo */ +#cwrap { + background: #f7f7f7; + margin-top: 0px; + padding-top: 80px; + padding-bottom: 100px; +} + +#cwrap h3 { + margin-bottom: 60px; +} + +/* Footer */ +#footerwrap { + padding-top: 60px; + padding-bottom: 60px; + background: #384452; +} + +#footerwrap p { + color: #bfc9d3; +} + +#footerwrap h4 { + color: white; +} + +#footerwrap i { + font-size: 30px; + color: #bfc9d3; + padding-right: 25px; +} + +#footerwrap i:hover { + color: #00b3fe +} + +/* ################################################################ + PAGE CONFIGURATIONS +################################################################# */ +/* General Tweaks */ + +#blue { + background: #00b3fe; + margin-top: 60px; + margin-bottom: 60px; + padding-top: 25px; + padding-bottom: 25px; +} + +#blue h3 { + color: white; + margin-left: 15px; +} + +.ctitle { + color: #00b3fe; + font-weight: 700; + margin-bottom: 15px; +} + +csmall { + font-size: 12px; + color: #b3b3b3; +} +csmall2 { + font-size: 12px; + color: #f39c12 +} + +.spacing { + margin-top: 40px; + margin-bottom: 40px; +} + +.badge-theme { + background: #00b3fe; +} + +/* Contact Page */ +#contactwrap { + background: url(../img/contact.jpg) no-repeat center top; + margin-top: -60px; + padding-top:0px; + text-align:center; + background-attachment: relative; + background-position: center center; + min-height: 400px; + width: 100%; + + -webkit-background-size: 100%; + -moz-background-size: 100%; + -o-background-size: 100%; + background-size: 100%; + + -webkit-background-size: cover; + -moz-background-size: cover; + -o-background-size: cover; + background-size: cover; +} + +/* Blog Page */ +.popular-posts { + margin: 0px; + padding-left: 0px; + } + +.popular-posts li { + list-style: none; + margin-bottom: 20px; + min-height: 70px; +} +.popular-posts li a, +.popular-posts li a:hover { + color:#2f2f2f; + text-decoration: none; + } + +.popular-posts li img { + float: left; + margin-right: 20px; + } + +.popular-posts li em { + font-family: 'Lato', sans-serif; + font-size: 12px; + color: #b3b3b3 + } + +.popular-posts p { + line-height: normal; + margin-bottom: auto; +} + +.share i { + padding-right: 15px; + font-size: 18px; +} diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 495f79c..c2746a5 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,14 @@ module ApplicationHelper def title - "hacker-product-news-hunt" + "RRHNClone." + end + + def link_to_list_item(name, link, options={}) + options = current_page?(link) ? {class: "active"} : {} + content_tag :li, options do + link_to name, link, options + end + end end diff --git a/app/helpers/user_item_votes_helper.rb b/app/helpers/user_item_votes_helper.rb index eb1c6c7..92eb2ae 100644 --- a/app/helpers/user_item_votes_helper.rb +++ b/app/helpers/user_item_votes_helper.rb @@ -1,10 +1,10 @@ module UserItemVotesHelper def link_to_upvote(object) - link_to 'like!', vote_item_path(object), method: :post + link_to 'like!', vote_item_path(object), method: :post, class: 'text-danger' end def link_to_downvote(object) - link_to 'unlike!', vote_item_path(object), method: :delete + link_to 'unlike!', vote_item_path(object), method: :delete, class: 'text-muted' end def render_votes_for_item(item) diff --git a/app/models/user.rb b/app/models/user.rb index 3d5d0b8..6850efc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -8,9 +8,9 @@ class User < ActiveRecord::Base end - validates :password, length: { minimum: 5 } - validates :password, confirmation: true - validates :password_confirmation, presence: true + validates :password, length: { minimum: 5 }, if: :password + validates :password, confirmation: true, if: :password + validates :password_confirmation, presence: true, if: :password validates :username, uniqueness: true, length: {minimum: 2} diff --git a/app/views/admin/items/index.html.erb b/app/views/admin/items/index.html.erb index d9ff244..3c27c29 100644 --- a/app/views/admin/items/index.html.erb +++ b/app/views/admin/items/index.html.erb @@ -1,8 +1,8 @@ -
<%= notice %>
-<%= flash[:notice] %>
-<%= flash[:alert] %>
-<%= flash[:notice] %>
+ <% end %> + + <% if flash[:alert] %> +<%= flash[:alert] %>
+ <% end %> +