diff --git a/.gitignore b/.gitignore index 3f798c97..e21f5f45 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,7 @@ coverage/ *~ # every fucking time, dolphin -.directory \ No newline at end of file +.directory +# lookin' at you, OS trash +.DS_Store +Thumbs.DB diff --git a/Gemfile b/Gemfile index f966887f..6351f278 100644 --- a/Gemfile +++ b/Gemfile @@ -79,4 +79,5 @@ group :development, :test do gem 'simplecov-json', require: false gem 'simplecov-rcov', require: false gem 'database_cleaner' + gem 'better_errors' end diff --git a/Gemfile.lock b/Gemfile.lock index b94af2ab..af406aa4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -46,6 +46,10 @@ GEM addressable (2.3.8) arel (6.0.0) bcrypt (3.1.10) + better_errors (2.1.1) + coderay (>= 1.0.0) + erubis (>= 2.6.6) + rack (>= 0.9.0) bootstrap-sass (3.2.0.2) sass (~> 3.2) bootstrap3-datetimepicker-rails (4.7.14) @@ -68,6 +72,7 @@ GEM cliver (0.3.2) cocaine (0.5.7) climate_control (>= 0.0.3, < 1.0) + coderay (1.1.0) coffee-rails (4.1.0) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) @@ -365,6 +370,7 @@ PLATFORMS DEPENDENCIES bcrypt (~> 3.1.7) + better_errors bootstrap-sass (~> 3.2.0.1) bootstrap3-datetimepicker-rails (~> 4.7.14) bootstrap_form diff --git a/app/assets/javascripts/settings.coffee b/app/assets/javascripts/settings.coffee index 5742e5b9..f5616cbf 100644 --- a/app/assets/javascripts/settings.coffee +++ b/app/assets/javascripts/settings.coffee @@ -48,4 +48,46 @@ cropper.attr 'src', e.target.result - fr.readAsDataURL(input.files[0]) \ No newline at end of file + fr.readAsDataURL(input.files[0]) + +($ document).on 'change', 'input#user_profile_header[type=file]', -> + input = ($ this)[0] + + ($ '#profile-header-crop-controls').slideUp 400, -> + if input.files and input.files[0] + fr = new FileReader() + ($ fr).on 'load', (e) -> + cropper = ($ '#profile-header-cropper') + preview = ($ '#profile-header-preview') + + updateVars = (data, action) -> + ($ '#crop_h_x').val Math.floor(data.x / data.scale) + ($ '#crop_h_y').val Math.floor(data.y / data.scale) + ($ '#crop_h_w').val Math.floor(data.w / data.scale) + ($ '#crop_h_h').val Math.floor(data.h / data.scale) +# rx = 100 / data.w +# ry = 100 / data.h +# ($ '#profile-picture-preview').css +# width: Math.round(rx * preview[0].naturalWidth) + 'px' +# height: Math.round(ry * preview[0].naturalHeight) + 'px' +# marginLeft: '-' + Math.round(rx * data.x) + 'px' +# marginTop: '-' + Math.round(ry * data.y) + 'px' + + cropper.on 'load', -> + width = 1500 + height = 500 + + cropper.guillotine + width: 1500 + height: 500 + onChange: updateVars + + updateVars cropper.guillotine('getData'), 'drag' # just because + + ($ '#cropper-zoom-out').click -> cropper.guillotine 'zoomOut' + ($ '#cropper-zoom-in').click -> cropper.guillotine 'zoomIn' + ($ '#profile-header-crop-controls').slideDown() + + cropper.attr 'src', e.target.result + + fr.readAsDataURL(input.files[0]) diff --git a/app/assets/stylesheets/scss/user.scss b/app/assets/stylesheets/scss/user.scss index dbb73a94..377b2f68 100644 --- a/app/assets/stylesheets/scss/user.scss +++ b/app/assets/stylesheets/scss/user.scss @@ -28,13 +28,11 @@ margin-top: 0.65em; } -.profile--header { - position: absolute; - z-index: 0; +#profile--header { + position: relative; + z-index: -1; width: 100%; - height: 300px; background-color: darken($navbar-inverse-bg, 10%); - background-size: cover; } .profile--panel .panel-heading { @@ -100,14 +98,20 @@ $colours: danger $brand-danger, text-decoration: line-through !important; } -.profile--panel-push-50 { +.profile--panel-push-inner { display: block; - height: 50px; + height: 60px; +} + +.profile--header-img { + display: block; + min-width: 900px; width: 100%; } -.profile--panel-push-200 { - display: block; - height: 180px; - width: 100%; -} \ No newline at end of file +@media(min-width: 767px) { + .container.headerable { + padding-top: 0; + margin-top: -30px; + } +} diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 4667e2b0..43d3451c 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -24,11 +24,12 @@ class UserController < ApplicationController end def update - user_attributes = params.require(:user).permit(:display_name, :profile_picture, :motivation_header, :website, + user_attributes = params.require(:user).permit(:display_name, :profile_picture, :profile_header, :motivation_header, :website, :location, :bio, :crop_x, :crop_y, :crop_w, :crop_h) if current_user.update_attributes(user_attributes) text = 'Your profile has been updated!' text += ' It might take a few minutes until your new profile picture is shown everywhere.' if user_attributes[:profile_picture] + text += ' It might take a few minutes until your new profile header is shown everywhere.' if user_attributes[:profile_header] flash[:success] = text else flash[:error] = 'An error occurred. ;_;' diff --git a/app/models/user.rb b/app/models/user.rb index b8dc904d..8a07e97a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -49,7 +49,14 @@ class User < ActiveRecord::Base default_url: "/images/:style/no_avatar.png", use_timestamp: false, processors: [:cropper] validates_attachment_content_type :profile_picture, :content_type => /\Aimage\/.*\Z/ + + has_attached_file :profile_header, styles: { web: "1500x350#", mobile: "450x105#", retina: "900x210#" }, + default_url: '/images/header/:style/no_header.jpg', use_timestamp: false, + processors: [:cropper] + validates_attachment_content_type :profile_header, :content_type => /\Aimage\/.*\Z/ + process_in_background :profile_picture + process_in_background :profile_header before_save do self.display_name = 'WRYYYYYYYY' if display_name == 'Dio Brando' diff --git a/app/views/user/edit.html.haml b/app/views/user/edit.html.haml index f5d6af9c..84c379af 100644 --- a/app/views/user/edit.html.haml +++ b/app/views/user/edit.html.haml @@ -16,7 +16,7 @@ .row#profile-picture-crop-controls{style: 'display: none;'} .col-sm-10.col-md-8 - %strong Adjust your new image + %strong Adjust your new avatar %img#profile-picture-cropper{src: current_user.profile_picture.url(:medium)} .col-sm-2.col-md-4 .btn-group @@ -25,6 +25,23 @@ %button#cropper-zoom-in.btn.btn-inverse{type: :button} %i.fa.fa-search-plus + .media + .pull-left + %img.img-rounded.header--img{src: current_user.profile_header.url(:mobile)} + .media-body + = f.file_field :profile_header + + .row#profile-header-crop-controls{style: 'display: none;'} + .col-sm-10.col-md-8 + %strong Adjust your new header + %img#profile-header-cropper{src: current_user.profile_header.url(:web)} + .col-sm-2.col-md-4 + .btn-group + %button#cropper-zoom-out.btn.btn-inverse{type: :button} + %i.fa.fa-search-minus + %button#cropper-zoom-in.btn.btn-inverse{type: :button} + %i.fa.fa-search-plus + = f.text_field :motivation_header, label: "Motivation header", placeholder: 'Ask me anything!' = f.text_field :website, label: "Website", placeholder: 'http://example.com' @@ -36,4 +53,7 @@ - for attrib in %i(crop_x crop_y crop_w crop_h) = f.hidden_field attrib, id: attrib - = f.submit "Save settings", class: 'btn btn-primary' \ No newline at end of file + - for attrib in %i(crop_h_x crop_h_y crop_h_w crop_h_h) + = f.hidden_field attrib, id: attrib + + = f.submit "Save settings", class: 'btn btn-primary' diff --git a/app/views/user/show.html.haml b/app/views/user/show.html.haml index 836d12b1..9b2cb3ee 100644 --- a/app/views/user/show.html.haml +++ b/app/views/user/show.html.haml @@ -1,10 +1,12 @@ -.profile--header -.container.j2-page +#profile--header.hidden-xs + %img.profile--header-img{src: current_user.profile_header.url(:web)} +#profile--panel-push-n.hidden-xs +.container.j2-page.headerable .col-md-3.col-xs-12.col-sm-4.j2-col-reset = render 'user/profile_info' .hidden-xs= render 'shared/links' .col-md-9.col-xs-12.col-sm-8.j2-col-reset - .profile--panel-push-200.hidden-xs + .profile--panel-push-inner.hidden-xs = render 'shared/questionbox' - unless @user.banned? #answers diff --git a/db/migrate/20150508144336_add_attachment_profile_header_to_users.rb b/db/migrate/20150508144336_add_attachment_profile_header_to_users.rb new file mode 100644 index 00000000..7cd1ae7e --- /dev/null +++ b/db/migrate/20150508144336_add_attachment_profile_header_to_users.rb @@ -0,0 +1,12 @@ +class AddAttachmentProfileHeaderToUsers < ActiveRecord::Migration + def change + change_table :users do |t| + t.attachment :profile_header + t.boolean :profile_header_processing + t.integer :crop_h_x + t.integer :crop_h_y + t.integer :crop_h_w + t.integer :crop_h_h + end + end +end diff --git a/db/schema.rb b/db/schema.rb index a18869e4..a2d647b9 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: 20150422024104) do +ActiveRecord::Schema.define(version: 20150508144336) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -28,12 +28,24 @@ ActiveRecord::Schema.define(version: 20150422024104) do add_index "answers", ["user_id", "created_at"], name: "index_answers_on_user_id_and_created_at", using: :btree + create_table "comment_smiles", force: :cascade do |t| + t.integer "user_id" + t.integer "comment_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "comment_smiles", ["comment_id"], name: "index_comment_smiles_on_comment_id", using: :btree + add_index "comment_smiles", ["user_id", "comment_id"], name: "index_comment_smiles_on_user_id_and_comment_id", unique: true, using: :btree + add_index "comment_smiles", ["user_id"], name: "index_comment_smiles_on_user_id", using: :btree + create_table "comments", force: :cascade do |t| t.string "content" t.integer "answer_id" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" + t.integer "smile_count", default: 0, null: false end add_index "comments", ["user_id", "created_at"], name: "index_comments_on_user_id_and_created_at", using: :btree @@ -206,9 +218,21 @@ ActiveRecord::Schema.define(version: 20150422024104) do t.boolean "privacy_allow_public_timeline", default: true t.boolean "privacy_allow_stranger_answers", default: true t.boolean "privacy_show_in_search", default: true - t.boolean "banned", default: false + t.boolean "permanently_banned", default: false t.boolean "blogger", default: false t.boolean "contributor", default: false + t.string "ban_reason" + t.datetime "banned_until" + t.integer "comment_smiled_count", default: 0, null: false + t.string "profile_header_file_name" + t.string "profile_header_content_type" + t.integer "profile_header_file_size" + t.datetime "profile_header_updated_at" + t.boolean "profile_header_processing" + t.integer "crop_h_x" + t.integer "crop_h_y" + t.integer "crop_h_w" + t.integer "crop_h_h" end add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree diff --git a/public/images/header/mobile/no_header.jpg b/public/images/header/mobile/no_header.jpg new file mode 100644 index 00000000..32083353 Binary files /dev/null and b/public/images/header/mobile/no_header.jpg differ diff --git a/public/images/header/original/no_header.jpg b/public/images/header/original/no_header.jpg new file mode 100644 index 00000000..2e951ed4 Binary files /dev/null and b/public/images/header/original/no_header.jpg differ diff --git a/public/images/header/retina/no_header.jpg b/public/images/header/retina/no_header.jpg new file mode 100644 index 00000000..9c2f59ad Binary files /dev/null and b/public/images/header/retina/no_header.jpg differ diff --git a/public/images/header/web/no_header.jpg b/public/images/header/web/no_header.jpg new file mode 100644 index 00000000..134ce05b Binary files /dev/null and b/public/images/header/web/no_header.jpg differ