- diff --git a/Gemfile b/Gemfile index 65d098434..60b15c197 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,7 @@ gem 'rails_admin' # mail +gem 'markerb', '~> 1.0.0' gem 'messagebus_ruby_api', '1.0.3' gem 'airbrake' gem 'newrelic_rpm' @@ -44,7 +45,7 @@ end group :heroku do gem 'pg' - gem 'unicorn', '~> 4.2.0', :require => false + gem 'unicorn', '~> 4.3.0', :require => false end gem 'settingslogic', :git => 'git://github.com/binarylogic/settingslogic.git' @@ -116,12 +117,12 @@ group :assets do # install Node.js or use 'therubyracer'. # # See https://github.com/sstephenson/execjs#readme for more supported runtimes - + # gem 'therubyracer', :platform => :ruby - + gem 'handlebars_assets' gem 'uglifier' - + # asset_sync is required as needed by application.rb gem "asset_sync", :require => nil end @@ -156,7 +157,7 @@ group :test do gem 'rspec-core', '~> 2.9.0' gem 'rspec-instafail', '>= 0.1.7', :require => false gem "rspec-rails", "~> 2.9.0" - gem 'selenium-webdriver' + gem 'selenium-webdriver', '2.22.0.rc1' gem 'webmock', :require => false gem 'sqlite3' diff --git a/Gemfile.lock b/Gemfile.lock index 9ece023aa..469537701 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,7 +110,7 @@ GEM carrierwave (0.5.8) activesupport (~> 3.0) cgi_multipart_eof_fix (2.5.0) - childprocess (0.3.1) + childprocess (0.3.2) ffi (~> 1.0.6) chronic (0.6.7) client_side_validations (3.1.4) @@ -259,12 +259,16 @@ GEM railties (>= 3.0.0) kgio (2.7.4) launchy (2.0.3) + libwebsocket (0.1.3) + addressable linecache (0.46) rbx-require-relative (> 0.0.4) mail (2.3.3) i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) + markerb (1.0.0) + redcarpet (>= 2.0) messagebus_ruby_api (1.0.3) mime-types (1.18) mini_magick (3.4) @@ -414,7 +418,9 @@ GEM ruby-hmac (0.4.0) ruby-oembed (0.8.7) ruby-progressbar (0.0.10) - rubyzip (0.9.7) + ruby_core_source (0.1.5) + archive-tar-minitar (>= 0.5.2) + rubyzip (0.9.8) sass (3.1.15) sass-rails (3.1.4) actionpack (~> 3.1.0) @@ -422,10 +428,11 @@ GEM sass (>= 3.1.4) sprockets (~> 2.0.0) tilt (~> 1.3.2) - selenium-webdriver (2.19.0) + selenium-webdriver (2.22.0.rc1) childprocess (>= 0.2.5) - ffi (~> 1.0.9) - multi_json (~> 1.0.4) + ffi (~> 1.0) + libwebsocket (~> 0.1.3) + multi_json (~> 1.0) rubyzip simple_oauth (0.1.5) sinatra (1.3.2) @@ -461,7 +468,7 @@ GEM uglifier (1.2.4) execjs (>= 0.3.0) multi_json (>= 1.0.2) - unicorn (4.2.1) + unicorn (4.3.1) kgio (~> 2.6) rack raindrops (~> 0.7) @@ -530,6 +537,7 @@ DEPENDENCIES json jwt linecache (= 0.46) + markerb (~> 1.0.0) messagebus_ruby_api (= 1.0.3) mini_magick (= 3.4) mobile-fu @@ -567,7 +575,7 @@ DEPENDENCIES rspec-rails (~> 2.9.0) ruby-oembed (~> 0.8.7) sass-rails (= 3.1.4) - selenium-webdriver + selenium-webdriver (= 2.22.0.rc1) settingslogic! spork (~> 1.0rc2) sqlite3 @@ -576,7 +584,7 @@ DEPENDENCIES twitter (= 2.0.2) typhoeus uglifier - unicorn (~> 4.2.0) + unicorn (~> 4.3.0) webmock whenever will_paginate diff --git a/README.md b/README.md index e3921568f..a0a30aa9c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Welcome to the Diaspora Project! +Diaspora* Diaspora is a privacy-aware, personally-controlled, do-it-all open source social network. Check out our [project site](http://diasporaproject.org). @@ -12,41 +12,47 @@ If you want to do something big, reach out on IRC or the mailing list first, so With Diaspora you can: -- Run and host your own pod and have control over your own social experience. -- Own your own data. -- Make friends across other pods seamlessly. +- Make cool stuff +- Share it across the web +- Own your own data -Documentation is available on our [wiki](https://github.com/diaspora/diaspora/wiki) - -[Pull Request Guidelines](https://github.com/diaspora/diaspora/wiki/Pull-Request-Guidelines) - -Before submitting code, feel free to sign our [Contributor License Agreement](https://github.com/diaspora/diaspora/wiki/New-CLA--12-13-10) [Sign Here](https://spreadsheets.google.com/a/joindiaspora.com/spreadsheet/viewform?formkey=dFdRTnY0TGtfaklKQXZNUndsMlJ2eGc6MQ) ## Quick Start: -Here's how you can get a development environment up and running. You can check out system-specific guides [here](https://github.com/diaspora/diaspora/wiki/Installation-Guides). +Here's how you can get a **[development](http://guides.rubyonrails.org/getting_started.html)** environment up and running. This is where any new pod runner should start, as well as people +looking to contribute to D*. This script assumes you have [a basic Rails setup installed](http://railsapps.github.com/installing-rails-3-1.html). -### Step 1: Download the script +### Step 1: Run the script and follow the on screen instructions. ``` curl https://raw.github.com/diaspora/diaspora/master/script/install.sh | /bin/sh ``` -### Step 2: Follow the instructions - -### Step 3: Run the the development server +### Step 2: Run the the development server ``` rails s ``` then visit 'http://localhost:3000' in your browser. -### Step 4: Run tests +### Step 3 (for developers): Run tests ``` rake ``` -## Resources: +### Want a production setup? Having trouble with install script? Want to install D* the slow way? + Look to more specific install guides [here](https://github.com/diaspora/diaspora/wiki/Installation-Guides). + +## Contributing +We love community contributions, and we work extra hard to make sure every code contribution is looked at and given feedback. +To help everyone involved, please review our [Pull Request Guidelines](https://github.com/diaspora/diaspora/wiki/Pull-Request-Guidelines) +to make sure all contributions are submitted smoothly. + +Documentation is available on our [wiki](https://github.com/diaspora/diaspora/wiki) + +Before submitting code, please sign our [Contributor License Agreement](https://github.com/diaspora/diaspora/wiki/New-CLA--12-13-10) [Sign Here](https://spreadsheets.google.com/a/joindiaspora.com/spreadsheet/viewform?formkey=dFdRTnY0TGtfaklKQXZNUndsMlJ2eGc6MQ) + +## More Resources: - [Wiki](https://github.com/diaspora/diaspora/wiki) - [Podmin Resources](https://github.com/diaspora/diaspora/wiki/Podmin-Resources) diff --git a/app/assets/images/buttons/bday@2x-white.png b/app/assets/images/buttons/bday@2x-white.png new file mode 100644 index 000000000..ab5940c25 Binary files /dev/null and b/app/assets/images/buttons/bday@2x-white.png differ diff --git a/app/assets/images/buttons/service-icons/fb@2x-white.png b/app/assets/images/buttons/service-icons/fb@2x-white.png new file mode 100644 index 000000000..2fb0b930c Binary files /dev/null and b/app/assets/images/buttons/service-icons/fb@2x-white.png differ diff --git a/app/assets/images/buttons/service-icons/tumblr@2x-white.png b/app/assets/images/buttons/service-icons/tumblr@2x-white.png new file mode 100644 index 000000000..48ce0dc3c Binary files /dev/null and b/app/assets/images/buttons/service-icons/tumblr@2x-white.png differ diff --git a/app/assets/images/buttons/service-icons/twitter@2x-white.png b/app/assets/images/buttons/service-icons/twitter@2x-white.png new file mode 100644 index 000000000..7b6aec6a0 Binary files /dev/null and b/app/assets/images/buttons/service-icons/twitter@2x-white.png differ diff --git a/app/assets/javascripts/app/app.js b/app/assets/javascripts/app/app.js index 21849fcac..4e361e477 100644 --- a/app/assets/javascripts/app/app.js +++ b/app/assets/javascripts/app/app.js @@ -42,7 +42,7 @@ var app = { Backbone.history.start({pushState: true}); // there's probably a better way to do this... - $("a[rel=backbone]").bind("click", function(evt){ + $("a[rel=backbone]").live("click", function(evt){ evt.preventDefault(); var link = $(this); diff --git a/app/assets/javascripts/app/forms/picture_form.js b/app/assets/javascripts/app/forms/picture_form.js index 92640363b..21f3ba64c 100644 --- a/app/assets/javascripts/app/forms/picture_form.js +++ b/app/assets/javascripts/app/forms/picture_form.js @@ -1,11 +1,35 @@ -app.forms.Picture = app.views.Base.extend({ - templateName : "picture-form", - +app.forms.PictureBase = app.views.Base.extend({ events : { 'ajax:complete .new_photo' : "photoUploaded", "change input[name='photo[user_file]']" : "submitForm" }, + onSubmit : $.noop, + uploadSuccess : $.noop, + + postRenderTemplate : function(){ + this.$("input[name=authenticity_token]").val($("meta[name=csrf-token]").attr("content")) + }, + + submitForm : function (){ + this.$("form").submit(); + this.onSubmit(); + }, + + photoUploaded : function(evt, xhr) { + resp = JSON.parse(xhr.responseText) + if(resp.success) { + this.uploadSuccess(resp) + } else { + alert("Upload failed! Please try again. " + resp.error); + } + } +}); + +/* multi photo uploader */ +app.forms.Picture = app.forms.PictureBase.extend({ + templateName : "picture-form", + initialize : function() { this.photos = new Backbone.Collection() this.photos.bind("add", this.render, this) @@ -17,18 +41,12 @@ app.forms.Picture = app.views.Base.extend({ this.renderPhotos(); }, - submitForm : function (){ - this.$("form").submit(); + onSubmit : function (){ this.$(".photos").append($('')) }, - photoUploaded : function(evt, xhr) { - resp = JSON.parse(xhr.responseText) - if(resp.success) { - this.photos.add(new Backbone.Model(resp.data)) - } else { - alert("Upload failed! Please try again. " + resp.error); - } + uploadSuccess : function(resp) { + this.photos.add(new Backbone.Model(resp.data)) }, renderPhotos : function(){ @@ -38,4 +56,13 @@ app.forms.Picture = app.views.Base.extend({ photoContainer.append(photoView) }) } +}); + +/* wallpaper uploader */ +app.forms.Wallpaper = app.forms.PictureBase.extend({ + templateName : "wallpaper-form", + + uploadSuccess : function(resp) { + $("#profile").css("background-image", "url(" + resp.data.wallpaper + ")") + } }); \ No newline at end of file diff --git a/app/assets/javascripts/app/models/profile.js b/app/assets/javascripts/app/models/profile.js index cf52af89b..43d04c8c4 100644 --- a/app/assets/javascripts/app/models/profile.js +++ b/app/assets/javascripts/app/models/profile.js @@ -2,6 +2,14 @@ app.models.Profile = Backbone.Model.extend({ urlRoot : "/profiles" }, { + preloadOrFetch : function(id){ + if(app.hasPreload("person")) { + return new app.models.Profile(app.parsePreload("person")) + } else { + return this.findByGuid(id) + } + }, + findByGuid : function(personId){ var person = new app.models.Profile({ id : personId}) person.fetch() diff --git a/app/assets/javascripts/app/models/user.js b/app/assets/javascripts/app/models/user.js index 5eaa87dab..0a9046df1 100644 --- a/app/assets/javascripts/app/models/user.js +++ b/app/assets/javascripts/app/models/user.js @@ -11,5 +11,9 @@ app.models.User = Backbone.Model.extend({ expProfileUrl : function(){ return "/people/" + app.currentUser.get("guid") + "?ex=true" + }, + + isServiceConfigured : function(providerName) { + return _.include(this.get("configured_services"), providerName) } }); diff --git a/app/assets/javascripts/app/pages/framer.js b/app/assets/javascripts/app/pages/framer.js index b6465405c..aab1e5c1e 100644 --- a/app/assets/javascripts/app/pages/framer.js +++ b/app/assets/javascripts/app/pages/framer.js @@ -59,5 +59,5 @@ app.views.framerControls = app.views.Base.extend({ //crazy hack for model publisher. function closeIFrame(){ - location.reload() + location = "/people/" + app.currentUser.get("guid") }; \ No newline at end of file diff --git a/app/assets/javascripts/app/pages/post-viewer.js b/app/assets/javascripts/app/pages/post-viewer.js index 832f95cc6..17b0c19f8 100644 --- a/app/assets/javascripts/app/pages/post-viewer.js +++ b/app/assets/javascripts/app/pages/post-viewer.js @@ -5,18 +5,13 @@ app.pages.PostViewer = app.views.Base.extend({ "#post-content" : "postView", "#post-nav" : "navView", "#post-interactions" : "interactionsView", - "#header-container" : "authorView" + "#author-info" : "authorView" }, initialize : function(options) { this.model = new app.models.Post({ id : options.id }); this.model.preloadOrFetch().done(_.bind(this.initViews, this)); - - this.prepIdleHooks(); - - $(document).bind("keypress", _.bind(this.commentAnywhere, this)) - $(document).bind("keypress", _.bind(this.invokePane, this)) - $(document).bind("keyup", _.bind(this.closePane, this)) + this.bindEvents() }, initViews : function() { @@ -29,6 +24,23 @@ app.pages.PostViewer = app.views.Base.extend({ this.render(); }, + bindEvents : function(){ + this.prepIdleHooks(); + this.bindNavHooks(); + + $(document).bind("keypress", _.bind(this.commentAnywhere, this)) + $(document).bind("keypress", _.bind(this.invokePane, this)) + $(document).bind("keyup", _.bind(this.closePane, this)) + }, + + unbind : function(){ + $(document).unbind("idle.idleTimer") + $(document).unbind("active.idleTimer") + $(document).unbind('keydown') + $(document).unbind('keypress') + $(document).unbind('keyup') + }, + prepIdleHooks : function () { $.idleTimer(3000); @@ -41,38 +53,25 @@ app.pages.PostViewer = app.views.Base.extend({ }); }, - postRenderTemplate : function() { - /* set the document title, if it has one */ - if(this.model.get("title")){ - document.title = this.model.get("title"); - } - this.bindNavHooks(); - }, - bindNavHooks : function() { - /* navagation hooks */ - var nextPostLocation = this.model.get("next_post"); - var previousPostLocation = this.model.get("previous_post"); - - + var model = this.model; $(document).keydown(function(evt){ - /* prevent nav from happening if the user is using the arrow - * keys to navigate through their comment text */ + // prevent nav from happening if the user is using the arrow keys to navigate through their comment text if($(evt.target).is("textarea")) { return } switch(evt.keyCode) { case 37: - navigate(nextPostLocation); break; + app.router.navigate(model.get("next_post"), true); break; case 39: - navigate(previousPostLocation); break; + app.router.navigate(model.get("previous_post"), true); break; default: break; } }) + }, - function navigate(loc) { - loc ? window.location = loc : null - } + postRenderTemplate : function() { + if(this.model.get("title")){ document.title = this.model.get("title"); } }, commentAnywhere : function(evt) { diff --git a/app/assets/javascripts/app/pages/profile.js b/app/assets/javascripts/app/pages/profile.js index 1915d7dc2..93afc54f4 100644 --- a/app/assets/javascripts/app/pages/profile.js +++ b/app/assets/javascripts/app/pages/profile.js @@ -2,13 +2,13 @@ //= require ../views/profile_info_view app.pages.Profile = app.views.Base.extend({ - className : "container", - templateName : "profile", + id : "profile", subviews : { "#profile-info" : "profileInfo", - "#canvas" : "canvasView" + "#canvas" : "canvasView", + "#wallpaper-upload" : "wallpaperForm" }, events : { @@ -21,23 +21,13 @@ app.pages.Profile = app.views.Base.extend({ personGUID : null, editMode : false, - presenter : function(){ - var bio = this.model.get("bio") || '' - - return _.extend(this.defaultPresenter(), - {text : this.model && app.helpers.textFormatter(bio, this.model), - isOwnProfile : this.isOwnProfile(), - showFollowButton : this.showFollowButton() - }) - }, - initialize : function(options) { this.personGUID = options.personId - this.model = new app.models.Profile.findByGuid(options.personId) + this.model = this.model || app.models.Profile.preloadOrFetch(this.personGUID) this.stream = options && options.stream || new app.models.Stream() - this.model.bind("change", this.setPageTitle, this) + this.model.bind("change", this.setPageTitleAndBackground, this) /* binds for getting started pulsation */ this.stream.bind("fetched", this.pulsateNewPostControl, this) @@ -46,9 +36,17 @@ app.pages.Profile = app.views.Base.extend({ this.stream.preloadOrFetch(); this.canvasView = new app.views.Canvas({ model : this.stream }) + this.wallpaperForm = new app.forms.Wallpaper() + this.profileInfo = new app.views.ProfileInfo({ model : this.model }) + }, - // send in isOwnProfile data - this.profileInfo = new app.views.ProfileInfo({ model : this.model.set({isOwnProfile : this.isOwnProfile()}) }) + presenter : function(){ + var bio = this.model.get("bio") || '' + + return _.extend(this.defaultPresenter(), + {text : this.model && app.helpers.textFormatter(bio, this.model), + showFollowButton : this.showFollowButton() + }) }, pulsateNewPostControl : function() { @@ -59,9 +57,11 @@ app.pages.Profile = app.views.Base.extend({ ]("pulse") }, - setPageTitle : function() { - if(this.model.get("name")) + setPageTitleAndBackground : function() { + if(this.model.get("name")) { document.title = this.model.get("name") + this.$el.css("background-image", "url(" + this.model.get("wallpaper") + ")") + } }, toggleEdit : function(evt) { @@ -81,10 +81,6 @@ app.pages.Profile = app.views.Base.extend({ }, showFollowButton : function() { - return this.followingEnabled() && !this.isOwnProfile() - }, - - isOwnProfile : function() { - return(app.currentUser.get("guid") == this.personGUID) + return this.followingEnabled() && !this.model.get("is_own_profile") } -}); \ No newline at end of file +}); diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js index 812b1bbc7..1af163bc0 100644 --- a/app/assets/javascripts/app/router.js +++ b/app/assets/javascripts/app/router.js @@ -23,25 +23,38 @@ app.Router = Backbone.Router.extend({ "posts/new" : "composer", "posts/:id": "singlePost", + "posts/:id/next": "siblingPost", + "posts/:id/previous": "siblingPost", + "p/:id": "singlePost", "framer": "framer" }, + siblingPost : function(){ //next or previous + var post = new app.models.Post(); + post.bind("change", setPreloadAttributesAndNavigate) + post.fetch({url : window.location}) + + function setPreloadAttributesAndNavigate(){ + window.preloads.post = post.attributes + app.router.navigate(post.url(), true) + } + }, newProfile : function(personId) { - this.renderPage(new app.pages.Profile({ personId : personId })); + this.renderPage(function(){ return new app.pages.Profile({ personId : personId })}); }, composer : function(){ - this.renderPage(new app.pages.Composer()); + this.renderPage(function(){ return new app.pages.Composer()}); }, framer : function(){ - this.renderPage(new app.pages.Framer()); + this.renderPage(function(){ return new app.pages.Framer()}); }, singlePost : function(id) { - this.renderPage(new app.pages.PostViewer({ id: id })); + this.renderPage(function(){ return new app.pages.PostViewer({ id: id })}); }, profile : function(page) { @@ -72,8 +85,9 @@ app.Router = Backbone.Router.extend({ return query.search("ex=true") != -1 }, - renderPage : function(page){ - app.page = page + renderPage : function(pageConstructor){ + app.page && app.page.unbind && app.page.unbind() //old page might mutate global events $(document).keypress, so unbind before creating + app.page = pageConstructor() //create new page after the world is clean (like that will ever happen) $("#container").html(app.page.render().el) } }); diff --git a/app/assets/javascripts/app/views/canvas_view.js b/app/assets/javascripts/app/views/canvas_view.js index a3e2f8ef5..ad2681227 100644 --- a/app/assets/javascripts/app/views/canvas_view.js +++ b/app/assets/javascripts/app/views/canvas_view.js @@ -10,9 +10,23 @@ app.views.Canvas = app.views.Base.extend(_.extend({}, app.views.infiniteScrollMi renderTemplate : function() { this.$el.empty() - this.stream.items.each(_.bind(function(post){ - this.$el.append(this.createPostView(post).render().el); - }, this)) + + if(this.stream.items.isEmpty()){ + var message + , person = app.page.model + if(person.get("is_own_profile")){ + message = "Make something to start the magic." + } else { + var name = person.get("name") || "" + message = name + " hasn't posted anything yet." + } + + this.$el.html("
") + } else { + this.stream.items.each(_.bind(function(post){ + this.$el.append(this.createPostView(post).render().el); + }, this)) + } //needs to be deferred so it happens after html rendering finishes _.defer(_.bind(this.mason, this)) @@ -29,6 +43,7 @@ app.views.Canvas = app.views.Base.extend(_.extend({}, app.views.infiniteScrollMi itemSelector : '.canvas-frame', visibleStyle : {scale : 1}, hiddenStyle : {scale : 0.001}, + containerStyle : {position : "relative"}, masonry : { columnWidth : 292.5 } diff --git a/app/assets/javascripts/app/views/post-viewer/author.js b/app/assets/javascripts/app/views/post-viewer/author.js index 0de915c93..af8e0aee2 100644 --- a/app/assets/javascripts/app/views/post-viewer/author.js +++ b/app/assets/javascripts/app/views/post-viewer/author.js @@ -3,6 +3,13 @@ app.views.PostViewerAuthor = app.views.Base.extend({ id : "post-author", className : "media", - templateName: "post-viewer/author" + tooltipSelector : ".profile-image-container", + + templateName: "post-viewer/author", + + initialize : function() { + /* add a class so we know how to color the text for the author name */ + this.$el.addClass(this.model.get("frame_name")) + } }); \ No newline at end of file diff --git a/app/assets/javascripts/app/views/post-viewer/nav.js b/app/assets/javascripts/app/views/post-viewer/nav.js index 1fa714fa6..575a42493 100644 --- a/app/assets/javascripts/app/views/post-viewer/nav.js +++ b/app/assets/javascripts/app/views/post-viewer/nav.js @@ -1,16 +1,3 @@ app.views.PostViewerNav = app.views.Base.extend({ - templateName: "post-viewer/nav", - - postRenderTemplate : function() { - var mappings = {"#forward" : "next_post", - "#back" : "previous_post"}; - - _.each(mappings, function(attribute, selector){ - this.setArrow(this.$(selector), this.model.get(attribute)) - }, this); - }, - - setArrow : function(arrow, loc) { - loc ? arrow.attr('href', loc) : arrow.remove() - } + templateName: "post-viewer/nav" }); \ No newline at end of file diff --git a/app/assets/javascripts/app/views/services_selector_view.js b/app/assets/javascripts/app/views/services_selector_view.js index 7ed3e3c99..a6ceef3c2 100644 --- a/app/assets/javascripts/app/views/services_selector_view.js +++ b/app/assets/javascripts/app/views/services_selector_view.js @@ -1,5 +1,30 @@ app.views.ServicesSelector = app.views.Base.extend({ - templateName : "services-selector" + templateName : "services-selector", -}); \ No newline at end of file + events : { + "click label" : "askForAuth" + }, + + tooltipSelector : "img", + + services : [ + 'facebook', + 'twitter', + 'tumblr' + ], + + presenter : function() { + return _.extend(this.defaultPresenter(), {services : this.services}) + }, + + askForAuth : function(evt){ + var $target = $(evt.target); + + if(app.currentUser.isServiceConfigured($target.data('provider'))) { return } + + var serviceUrl = $target.data('url') + window.open(serviceUrl, 'popup', 'height=400,width=500') + } + +}); diff --git a/app/assets/javascripts/app/views/small_frame.js b/app/assets/javascripts/app/views/small_frame.js index 0061621e5..64f69a0c2 100644 --- a/app/assets/javascripts/app/views/small_frame.js +++ b/app/assets/javascripts/app/views/small_frame.js @@ -71,7 +71,7 @@ app.views.SmallFrame = app.views.Post.extend({ }, adjustedImageHeight : function() { - if(!this.model.get("photos")[0]) { return } + if(!(this.model.get("photos") || [])[0]) { return } var modifiers = [this.dimensionsClass(), this.colorClass()].join(' ') diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass index 06de2f1c8..d21cc3c3d 100644 --- a/app/assets/stylesheets/application.css.sass +++ b/app/assets/stylesheets/application.css.sass @@ -1818,6 +1818,8 @@ ul#press_logos :overflow hidden :position relative p + :margin 0 0 0.8em + p:nth-last-child(2) :margin 0 .expander diff --git a/app/assets/stylesheets/new_styles/_base.scss b/app/assets/stylesheets/new_styles/_base.scss index e3610c3c6..bed2a0df2 100644 --- a/app/assets/stylesheets/new_styles/_base.scss +++ b/app/assets/stylesheets/new_styles/_base.scss @@ -1,3 +1,7 @@ +body { + background-image : image_url("pattern.png"); +} + /* new link color */ a { color : rgb(42,156,235) } @@ -5,12 +9,6 @@ a { color : rgb(42,156,235) } .icon-red { background-image: image_url("img/glyphicons-halflings-red.png"); } .icon-blue { background-image: image_url("img/glyphicons-halflings-blue.png"); } - @media (max-width: 770px) { //why is 770 a magic number? - body { - padding: 0; - } - } - .photoset { @include center(horizontal); width: 100%; @@ -58,30 +56,6 @@ a { color : rgb(42,156,235) } vertical-align: middle; } -.header { - position: fixed; - - /* position absolute for mobile */ - @media (max-width: 480px) { - position: absolute !important; - } - - top: 0; - left: 0; - z-index: 10; - width: 100%; - overflow-x: hidden; -} - -#header-container { - padding: 1.2%; - - /* don't pad the header if we're mobile */ - @media (max-width: 480px) { - padding: 0 !important; - } -} - .avatar { &.micro { height: 20px; @@ -95,46 +69,46 @@ a { color : rgb(42,156,235) } } .author-name { + font-family : Roboto; color: inherit; - font-weight: bold; } -#post-author { - @include border-radius(); +#author-info { + position : absolute; + z-index : 300; - border: 1px solid rgba(255,255,255,0.2); - border-top: 1px solid rgba(255,255,255,0.5); - - float: left; - margin: 0; - - padding: 5px; - padding-right: 10px; - - background-color: rgba(255,255,255,0.6); - -/* don't pad the header if we're mobile */ - @media (max-width: 480px) { - @include border-radius(0); - background-color: rgba(255,255,255,0.4); - width: 100% !important; - border: none !important; - padding: none !important; + .author-name { + color: #555; } - max-height: 35px; - - .avatar { - @include border-radius(); + .bd { + margin-top : 5px; } .post-time, .icon-retweet { - color: #000; + color: #555; @include opacity(0.5); } } +#post-author { + margin : 0; + padding : 10px; + + &.status-with-photo-backdrop, + &.Wallpaper { + .author-name { + color : #fff; + } + + .post-time, + .icon-retweet { + color: #fff; + @include opacity(0.5); + } + } +} .post-view { display: table; @@ -203,6 +177,10 @@ article { //mood posts background-color : $night-background-color; color : $night-text-color; + #author-info { + color : $night-text-color; + } + .photo-viewer { img { max-height: 80%; @@ -240,9 +218,6 @@ article { //mood posts &.wallpaper{ color : #fff; - header { - margin: 0 7%; - } } &.multi-photo { @@ -441,17 +416,23 @@ div[data-template=flow] { label { display : inline;} img { + @include transition(opacity); + cursor : pointer; height : 28px; width : 28px; - - &:hover { - @include opacity(0.6); - } } input:not(:checked) + label { - @include opacity(0.4); + img { + @include opacity(0.4); + } + } + + input:checked + label { + &:hover img { + @include opacity(1); + } } input { @@ -466,19 +447,6 @@ div[data-template=flow] { right : 10px; top : 10px; - - .label { - padding : 2px 5px; - padding-bottom : 3px; - - span { - display : inline-block; - position : relative; - top : 1px; - font-family : Roboto-Bold; - } - } - & > a { @include transition(opacity); @include opacity(0.4); @@ -490,4 +458,17 @@ div[data-template=flow] { text-decoration : none; } } -} \ No newline at end of file +} + +/* bootstrap label fixes for Roboto */ +.label { + padding : 2px 5px; + padding-bottom : 3px; + + span { + display : inline-block; + position : relative; + top : 1px; + font-family : Roboto-Bold; + } +} diff --git a/app/assets/stylesheets/new_styles/_canvas.scss b/app/assets/stylesheets/new_styles/_canvas.scss index fc8455bec..239ac6241 100644 --- a/app/assets/stylesheets/new_styles/_canvas.scss +++ b/app/assets/stylesheets/new_styles/_canvas.scss @@ -1,18 +1,18 @@ - @mixin wide() { width : $two-column-width + px; min-width : $two-column-width + px; max-width : $two-column-width + px; } - -body { - background-color : #F6F6F6; - background-image : image_url('pattern.png') +.no-post-message { + text-align: center; + margin-top: 50px; + font-size: 1.2em; } .canvas-frame { float : left; margin : 10px; + margin-bottom : 18px; /* expand / contract cursor declarations */ &.x2 .content { @@ -28,12 +28,12 @@ body { .content { @include transition(box-shadow); - @include box-shadow(0,1px,3px,rgba(0,0,0,0.2)); + @include box-shadow(0, 8px, 50px, rgba(0,0,0,0.9)); background-image : image_url("paper-texture-1.jpg"); &:hover { - @include box-shadow(0,1px,5px,rgba(0,0,0,0.5)); + @include box-shadow(0, 3px, 10px,rgba(0,0,0,0.9)); .info { top : 0; @@ -59,11 +59,9 @@ body { max-width : $column-width + px; overflow : hidden; - //padding : 20px; /* used in masking photos with overflow: hidden; */ .image-container { - overflow : hidden; width : 100%; @@ -128,6 +126,8 @@ body { background-color : rgba(255,255,255,0.8); border-bottom : 1px solid #fff; + color : #000; + position : absolute; top : -32px; right : 0; diff --git a/app/assets/stylesheets/new_styles/_composer.scss b/app/assets/stylesheets/new_styles/_composer.scss index 7b8e8114a..89e5af3d3 100644 --- a/app/assets/stylesheets/new_styles/_composer.scss +++ b/app/assets/stylesheets/new_styles/_composer.scss @@ -11,9 +11,7 @@ #photo_upload_button { position: relative; - margin : { - bottom : 9px; - } + margin-bottom : 9px; input{ @include opacity(0); @@ -21,6 +19,7 @@ top: 0; left: 0; height:100%; + cursor : pointer; } } diff --git a/app/assets/stylesheets/new_styles/_profile.scss b/app/assets/stylesheets/new_styles/_profile.scss index 300326ab9..f558be3a3 100644 --- a/app/assets/stylesheets/new_styles/_profile.scss +++ b/app/assets/stylesheets/new_styles/_profile.scss @@ -1,3 +1,26 @@ +#profile { + min-height : 100%; + + color : #fff; + background : { + color : #333; + + /* The background-image property will be user-generated and set in `app.pages.Profile` (app/assets/javascripts/app/pages/profile.js) + and should ONLY be set once the image is fully loaded. + + Optimal imagemagick manipulation settings for uploaded image (via trial & error): + + `mogrify -brightness-contrast -40x-50` + + NOTE: I noticed that just turning the brightness down had an adverse affect on contrast, + thus the "washing out" at -50 contrast. For more info on this specific command, read the documentation + on it here: http://www.imagemagick.org/script/command-line-options.php#brightness-contrast */ + + size : cover; + attachment : fixed; + } +} + /* getting started pulse animation */ #composer-button.pulse { -webkit-animation: opacity-pulse 1s infinite; @@ -35,6 +58,18 @@ display : inline-block; margin-bottom : 5px; + + &.small { + height : 40px; + width : 40px; + border : 2px solid #fff; + } + + &.micro { + height : 24px; + width : 24px; + border : 2px solid #fff; + } } #profile-controls { diff --git a/app/assets/templates/canvas.jst.hbs b/app/assets/templates/canvas.jst.hbs deleted file mode 100644 index eba934a52..000000000 --- a/app/assets/templates/canvas.jst.hbs +++ /dev/null @@ -1,173 +0,0 @@ -
- - Here, he discusses how globalisation has exacerbated income inequalities and the control over politics exerted by the rich, citing the Occupy movement which he describes as a 'public relations hazard not a health hazard' -
- -- Echo park wolf kale chips sunt, dolor scenester deserunt ad cray leggings 3 wolf moon thundercats direct trade. Banksy placeat odd future et, ex gastropub elit whatever. Messenger bag eu fanny pack, pitchfork locavore four loko yr marfa forage. Mcsweeney's hoodie terry richardson exercitation, consectetur commodo banh mi ullamco laboris cliche raw denim salvia selvage in nulla. Lo-fi chambray culpa, dreamcatcher fugiat squid portland nihil high life. Quis VHS blog sunt sint, salvia wes anderson fingerstache portland eiusmod ex consectetur synth enim. Tattooed aliquip proident id, lomo aliqua qui pitchfork hella cosby sweater pariatur vero.
- -
- - Echo park wolf kale chips sunt, dolor scenester deserunt ad cray leggings 3 wolf moon thundercats direct trade. Banksy placeat odd future et, ex gastropub elit whatever. Messenger bag eu fanny pack, pitchfork locavore four loko yr marfa forage. Mcsweeney's hoodie terry richardson exercitation, consectetur commodo banh mi ullamco laboris cliche raw denim salvia selvage in nulla. Lo-fi chambray culpa, dreamcatcher fugiat squid portland nihil high life. Quis VHS blog sunt sint, salvia wes anderson fingerstache portland eiusmod ex consectetur synth enim. Tattooed aliquip proident id, lomo aliqua qui pitchfork hella cosby sweater pariatur vero. -
- -
-
-
- - Banksy placeat odd future et, ex gastropub elit whatever. Messenger bag eu fanny pack, pitchfork locavore four loko yr marfa forage. Mcsweeney's hoodie terry richardson exercitation, consectetur commodo banh mi ullamco laboris cliche raw denim salvia selvage -
-
-