diff --git a/.ruby-version b/.ruby-version index 585940699..276cbf9e2 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.2.3 +2.3.0 diff --git a/Gemfile.lock b/Gemfile.lock index 450d0f27b..b3c908001 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -74,9 +74,9 @@ GEM bcrypt (3.1.11) browser (2.1.0) builder (3.2.2) - bullet (5.0.0) + bullet (5.1.0) activesupport (>= 3.0.0) - uniform_notifier (~> 1.9.0) + uniform_notifier (~> 1.10.0) byebug (9.0.4) cancancan (1.14.0) capistrano (3.4.1) @@ -228,9 +228,9 @@ GEM nokogiri (>= 1.5.9) mail (2.6.4) mime-types (>= 1.16, < 4) - mime-types (3.0) + mime-types (3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0221) + mime-types-data (3.2016.0521) mini_portile2 (2.0.0) minitest (5.9.0) multi_json (1.12.1) @@ -275,7 +275,7 @@ GEM parser (2.3.0.6) ast (~> 2.2) pg (0.18.4) - pg_search (1.0.5) + pg_search (1.0.6) activerecord (>= 3.1) activesupport (>= 3.1) arel @@ -413,7 +413,7 @@ GEM unicorn (5.1.0) kgio (~> 2.6) raindrops (~> 0.7) - uniform_notifier (1.9.0) + uniform_notifier (1.10.0) user_agent_parser (2.3.0) uuidtools (2.1.5) warden (1.2.6) diff --git a/README.md b/README.md index 0ee254d3a..ba1c6cf21 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ cp config/secrets.yml.example config/secrets.yml rake db:create bin/rake db:setup bin/rake db:dev_seed -RAILS_ENV=test bin/rake db:setup +RAILS_ENV=test rake db:setup ``` Run the app locally: diff --git a/README_ES.md b/README_ES.md index 9ae368848..455215abe 100644 --- a/README_ES.md +++ b/README_ES.md @@ -39,7 +39,7 @@ cp config/secrets.yml.example config/secrets.yml rake db:create bin/rake db:setup bin/rake db:dev_seed -RAILS_ENV=test bin/rake db:setup +RAILS_ENV=test rake db:setup ``` Para ejecutar la aplicación en local: diff --git a/app/assets/images/banners/banner1.png b/app/assets/images/banners/banner1.png new file mode 100644 index 000000000..eff1cb9d7 Binary files /dev/null and b/app/assets/images/banners/banner1.png differ diff --git a/app/assets/images/banners/banner2.png b/app/assets/images/banners/banner2.png new file mode 100644 index 000000000..8ae0715e2 Binary files /dev/null and b/app/assets/images/banners/banner2.png differ diff --git a/app/assets/images/banners/banner3.png b/app/assets/images/banners/banner3.png new file mode 100644 index 000000000..e4ff49093 Binary files /dev/null and b/app/assets/images/banners/banner3.png differ diff --git a/app/assets/javascripts/advanced_search.js.coffee b/app/assets/javascripts/advanced_search.js.coffee index a5e657633..b38efb874 100644 --- a/app/assets/javascripts/advanced_search.js.coffee +++ b/app/assets/javascripts/advanced_search.js.coffee @@ -23,6 +23,8 @@ App.AdvancedSearch = $('.js-calendar').datepicker regional: locale maxDate: "+0d" + $('.js-calendar-full').datepicker + regional: locale initialize: -> App.AdvancedSearch.init_calendar() diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e24d144bb..a1b8dd70a 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -44,6 +44,7 @@ //= require tracks //= require valuation_spending_proposal_form //= require embed_video +//= require banners var initialize_modules = function() { App.Comments.initialize(); @@ -63,6 +64,7 @@ var initialize_modules = function() { App.Tracks.initialize(); App.ValuationSpendingProposalForm.initialize(); App.EmbedVideo.initialize(); + App.Banners.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/banners.js.coffee b/app/assets/javascripts/banners.js.coffee new file mode 100644 index 000000000..ec00abe95 --- /dev/null +++ b/app/assets/javascripts/banners.js.coffee @@ -0,0 +1,25 @@ +App.Banners = + + update_banner: (selector, text) -> + $(selector).html(text) + + update_style: (selector, style) -> + $(selector).removeClass($(selector).attr("class"), true) + .addClass(style, true) + + initialize: -> + $('[data-js-banner-title]').on + change: -> + App.Banners.update_banner("#js-banner-title", $(this).val()) + + $('[data-js-banner-description]').on + change: -> + App.Banners.update_banner("#js-banner-description", $(this).val()) + + $("#banner_style").on + change: -> + App.Banners.update_style("#js-banner-style", $(this).val()) + + $("#banner_image").on + change: -> + App.Banners.update_style("#js-banner-image", $(this).val()) diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 48642841d..f52045c7b 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -8,11 +8,27 @@ // // 01. Global styles -// - - - - - - - - - - - - - - - - - - - - - - - - - +// ----------------- + +$admin-color: #CF3638; body.admin { + header { + border: 0; + + .top-links { + background: darken($admin-color, 15%); + } + } + + .top-bar { + background: $admin-color !important; + height: auto; + } + form { + .button { margin-top: 0; } @@ -27,48 +43,40 @@ body.admin { table { + th { + text-align: left; + } + tr { - background: #f4f4f4; + background: white; + border: 1px solid $border; - &:nth-child(odd) { - background: white; - } - - &:nth-child(even) { - background: #f0f0f0; + &:hover { + background: #f3f6f7; } } - td.small { - font-size: $small-font-size; + input[type="submit"] ~ a, a ~ a { + margin-left: $line-height/2; + margin-right: $line-height/2; } } + hr { + max-width: none; + } + + .menu.simple li.active { + border-bottom: 2px solid $admin-color; + color: $admin-color; + } + #proposals { width: 100% !important; } - .dashboard { - margin-bottom: rem-calc(48); - - ul, ol { - margin-left: rem-calc(12); - - li { - font-size: rem-calc(15); - line-height: rem-calc(30); - margin-bottom: rem-calc(12); - } - } - - p { - font-size: rem-calc(15); - line-height: rem-calc(30); - } - - h3 { - font-weight: bold; - } + .accordion-title { + font-size: $base-font-size; } .button.secondary { @@ -99,17 +107,37 @@ body.admin { display: none; } +.admin-content { + padding: $line-height !important; +} + +@include breakpoint(medium) { + + tr { + + .on-hover { + display: none; + } + + &:hover .on-hover { + display: inline; + } + } +} + // 02. Sidebar -// - - - - - - - - - - - - - - - - - - - - - - - - - +// ----------- .admin-sidebar { + border-right: 1px solid $border; - a { - color: white\9 !important; + @include breakpoint(medium) { + padding-bottom: $line-height*3; } ul { list-style-type: none; + margin-bottom: 0; margin-left: 0; padding: 0; @@ -120,83 +148,44 @@ body.admin { padding-top: rem-calc(4); padding-left: 12px\9 !important; padding-right: 12px\9 !important; + vertical-align: middle; } li { - background: #2E343F; - border-bottom: 1px solid #292f39; - border-top: 1px solid #353c49; + background: white; margin: 0; outline: 0; - &:first-child { + &.active a { + background: #f3f6f7; + color: $admin-color; font-weight: bold; - text-transform: uppercase; - } - - &.active{ - background: #373D47; - - a:not(.button) { - color: white; - } } } - li a:not(.button) { - color: rgba(255,255,255,0.3); + li.section { + border-bottom: 1px dotted #d5d5d5; + border-top: 1px dotted #d5d5d5; + height: $line-height/2; + } + + li a { + color: $text; + display: block; line-height: rem-calc(48); padding-left: rem-calc(12); vertical-align: top; &:hover { - color: white; + background: #f3f6f7; + text-decoration: none; } } } } // 03. List elements -// - - - - - - - - - - - - - - - - - - - - - - - - - - -.admin-list { - list-style-type: none; - margin: 0; - margin-bottom: rem-calc(48); - - form { - clear: both; - - .checkbox { - font-size: $small-font-size; - } - } - - li { - border-bottom: 1px solid #E7E9EC; - font-size: rem-calc(14); - min-height: rem-calc(72); - padding: rem-calc(12); - - &:first-child { - border-top: 1px solid #E7E9EC; - } - - &:nth-child(odd) { - background: #F0F2F6; - } - } - - .tag { - float: left; - font-size: rem-calc(18); - padding: 0; - } - - .button { - margin: 0; - } -} +// ----------------- .delete { border-bottom: 1px dotted #CF2A0E; @@ -239,14 +228,9 @@ body.admin { font-style: italic; } -.level { - font-size: rem-calc(12); -} - .official { background-color: #e7e7e7; border-radius: rem-calc(3); - font-size: rem-calc(12); font-weight: normal; padding: rem-calc(6) rem-calc(12); } @@ -262,13 +246,10 @@ body.admin { .moderation-description { max-height: rem-calc(65); overflow: hidden; - max-width: rem-calc(590); + max-width: rem-calc(700); &:hover { - cursor: text; max-height: rem-calc(1000); - outline: 3px solid #ffbf47; - padding: rem-calc(12); transition: max-height 0.9s; -moz-transition: max-height 0.9s; -webkit-transition: max-height 0.9s; @@ -276,7 +257,7 @@ body.admin { } // 04. Stats -// - - - - - - - - - - - - - - - - - - - - - - - - - +// --------- .stats { background: white; @@ -304,7 +285,7 @@ body.admin { } // 05. Management -// - - - - - - - - - - - - - - - - - - - - - - - - - +// -------------- .user-permissions { @@ -337,8 +318,8 @@ body.admin { border-radius: rem-calc(3); font-size: rem-calc(16); font-weight: normal; - margin-bottom: rem-calc(12); - padding: rem-calc(6) rem-calc(12); + margin: $line-height; + padding: $line-height/2; strong { font-size: rem-calc(18); diff --git a/app/assets/stylesheets/datepicker_overrides.scss b/app/assets/stylesheets/datepicker_overrides.scss index 88f17c7cc..dbbab4bd5 100644 --- a/app/assets/stylesheets/datepicker_overrides.scss +++ b/app/assets/stylesheets/datepicker_overrides.scss @@ -51,7 +51,7 @@ border-right: 1px solid $dark; tr th { - color: white; + color: $dark; } } diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index bbe74ac3d..b5a7ff714 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -17,6 +17,7 @@ // 15. Comments // 16. Flags // 17. Activity +// 18. Banners // // 01. Global styles @@ -218,6 +219,10 @@ a { float: left; } +.no-max-width { + max-width: none; +} + // 02. Header // ---------- @@ -1686,3 +1691,69 @@ table { } } } + +// 18. Banners +// ----------- + +.banner-style-one { + background-color: $brand; +} + +.banner-style-two { + background-color: $budget; +} + +.banner-style-three { + background-color: #33DADF; +} + +@include breakpoint(large) { + + .banner-img-one { + background-image: image-url('banners/banner1.png'); + } + + .banner-img-two { + background-image: image-url('banners/banner2.png'); + } + + .banner-img-three { + background-image: image-url('banners/banner3.png'); + } +} + +.banner-img-one, .banner-img-two, .banner-img-three { + background-position: bottom right; + background-repeat: no-repeat; +} + +.banner-style-one, .banner-style-two, .banner-style-three { + margin: 0; + margin-bottom: $line-height; + + h2, h3, a { + color: #eaeaf2; + } + + h2 { + padding: $line-height/2; + padding-bottom: 0; + } + + h3 { + padding: $line-height/2; + padding-top: 0; + } + + a:hover h2, a:hover h3 { + color: #eaeaf2 !important; + text-decoration: none; + } + + @include breakpoint(large) { + + h3 { + width: 80%; + } + } +} diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss index b1947768b..d772b8ace 100644 --- a/app/assets/stylesheets/mixins.scss +++ b/app/assets/stylesheets/mixins.scss @@ -8,6 +8,7 @@ @mixin logo { color: white; + display: inline-block; font-family: 'Lato' !important; font-size: rem-calc(24); font-weight: lighter; diff --git a/app/assets/stylesheets/print.css b/app/assets/stylesheets/print.css index 29096ae13..de5a56a31 100644 --- a/app/assets/stylesheets/print.css +++ b/app/assets/stylesheets/print.css @@ -12,6 +12,8 @@ #print_link { display: none !important; } +#responsive-menu { display: none !important; } + .admin-sidebar { display: none !important; } img.left { display: none !important; } diff --git a/app/controllers/admin/banners_controller.rb b/app/controllers/admin/banners_controller.rb new file mode 100644 index 000000000..dbf683b9a --- /dev/null +++ b/app/controllers/admin/banners_controller.rb @@ -0,0 +1,56 @@ +class Admin::BannersController < Admin::BaseController + + has_filters %w{all with_active with_inactive}, only: :index + + before_action :find_banner, only: [:edit, :update, :destroy] + before_action :banner_styles, only: [:edit, :new, :create, :update] + before_action :banner_imgs, only: [:edit, :new, :create, :update] + + respond_to :html, :js + + load_and_authorize_resource + + def index + @banners = Banner.send(@current_filter).page(params[:page]) + end + + def create + @banner = Banner.new(banner_params) + if @banner.save + redirect_to admin_banners_path + else + render :new + end + end + + def update + @banner.assign_attributes(banner_params) + if @banner.update(banner_params) + redirect_to admin_banners_path + else + render :edit + end + end + + def destroy + @banner.destroy + redirect_to admin_banners_path + end + + private + def banner_params + params.require(:banner).permit(:title, :description, :target_url, :style, :image, :post_started_at, :post_ended_at) + end + + def find_banner + @banner = Banner.find(params[:id]) + end + + def banner_styles + @banner_styles = Setting.all.banner_style.map { |banner_style| [banner_style.value, banner_style.key.split('.')[1]] } + end + + def banner_imgs + @banner_imgs = Setting.all.banner_img.map { |banner_img| [banner_img.value, banner_img.key.split('.')[1]] } + end +end \ No newline at end of file diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index 387f38177..17bd364f3 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -1,9 +1,11 @@ class Admin::SettingsController < Admin::BaseController def index - all_settings = (Setting.all).group_by { |s| s.feature_flag? } - @settings = all_settings[false] - @feature_flags = all_settings[true] + all_settings = (Setting.all).group_by { |s| s.type } + @settings = all_settings['common'] + @feature_flags = all_settings['feature'] + @banner_styles = all_settings['banner-style'] + @banner_imgs = all_settings['banner-img'] end def update diff --git a/app/controllers/concerns/commentable_actions.rb b/app/controllers/concerns/commentable_actions.rb index de2a2276a..3a79238ea 100644 --- a/app/controllers/concerns/commentable_actions.rb +++ b/app/controllers/concerns/commentable_actions.rb @@ -11,6 +11,8 @@ module CommentableActions index_customization if index_customization.present? @tag_cloud = tag_cloud + @banners = Banner.with_active + set_resource_votes(@resources) set_resources_instance end diff --git a/app/helpers/banners_helper.rb b/app/helpers/banners_helper.rb new file mode 100644 index 000000000..548513c7d --- /dev/null +++ b/app/helpers/banners_helper.rb @@ -0,0 +1,5 @@ +module BannersHelper + def has_banners + @banners.count > 0 + end +end \ No newline at end of file diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index b86723c93..42e4ecbd3 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -46,6 +46,8 @@ module Abilities can [:hide, :update], Budget::Investment can :valuate, Budget::Investment, budget: { valuating: true } can :create, Budget::ValuatorAssignment + + can [:search, :edit, :update, :create, :index, :destroy], Banner end end end diff --git a/app/models/banner.rb b/app/models/banner.rb new file mode 100644 index 000000000..db8f10635 --- /dev/null +++ b/app/models/banner.rb @@ -0,0 +1,20 @@ +class Banner < ActiveRecord::Base + + acts_as_paranoid column: :hidden_at + include ActsAsParanoidAliases + + validates :title, presence: true, + length: { minimum: 2 } + validates :description, presence: true + validates :target_url, presence: true + validates :style, presence: true + validates :image, presence: true + validates :post_started_at, presence: true + validates :post_ended_at, presence: true + + scope :with_active, -> {where("post_started_at <= ?", Time.now). + where("post_ended_at >= ?", Time.now) } + + scope :with_inactive,-> {where("post_started_at > ? or post_ended_at < ?", Time.now, Time.now) } + +end \ No newline at end of file diff --git a/app/models/setting.rb b/app/models/setting.rb index 40659ed74..9010abba5 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -2,6 +2,20 @@ class Setting < ActiveRecord::Base validates :key, presence: true, uniqueness: true default_scope { order(id: :asc) } + scope :banner_style, -> { where("key ilike ?", "banner-style.%")} + scope :banner_img, -> { where("key ilike ?", "banner-img.%")} + + def type + if feature_flag? + 'feature' + elsif banner_style? + 'banner-style' + elsif banner_img? + 'banner-img' + else + 'common' + end + end def feature_flag? key.start_with?('feature.') @@ -11,6 +25,14 @@ class Setting < ActiveRecord::Base feature_flag? && value.present? end + def banner_style? + key.start_with?('banner-style.') + end + + def banner_img? + key.start_with?('banner-img.') + end + class << self def [](key) where(key: key).pluck(:value).first.presence diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index bf0382dbd..7ea48b2c6 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -1,115 +1,103 @@