diff --git a/.rspec b/.rspec index 174e25596..554b09b48 100644 --- a/.rspec +++ b/.rspec @@ -3,3 +3,4 @@ --color --tag ~performance --order random +--require spec_helper diff --git a/Changelog.md b/Changelog.md index fb6e287d7..e7fe7f459 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,38 @@ +# 0.6.2.0 + +## Refactor +* Use string-direction gem for rtl detection [#7181](https://github.com/diaspora/diaspora/pull/7181) +* Reduce i18n.load side effects [#7184](https://github.com/diaspora/diaspora/pull/7184) +* Force jasmine fails on syntax errors [#7185](https://github.com/diaspora/diaspora/pull/7185) +* Don't display mail-related view content if it is disabled in the pod's config [#7190](https://github.com/diaspora/diaspora/pull/7190) +* Use typeahead.js from rails-assets.org [#7192](https://github.com/diaspora/diaspora/pull/7192) +* Refactor ShareVisibilitesController to use PostService [#7196](https://github.com/diaspora/diaspora/pull/7196) +* Unify desktop and mobile head elements [#7194](https://github.com/diaspora/diaspora/pull/7194) [#7209](https://github.com/diaspora/diaspora/pull/7209) +* Refactor flash messages on ajax errors for comments, likes, reshares and aspect memberships [#7202](https://github.com/diaspora/diaspora/pull/7202) +* Only require AWS-module for fog [#7201](https://github.com/diaspora/diaspora/pull/7201) +* Only show community spotlight links on the contacts page if community spotlight is enabled [#7213](https://github.com/diaspora/diaspora/pull/7213) +* Require spec\_helper in .rspec [#7223](https://github.com/diaspora/diaspora/pull/7223) +* Make the CSRF mail a bit more friendly [#7238](https://github.com/diaspora/diaspora/pull/7238) [#7241](https://github.com/diaspora/diaspora/pull/7241) + +## Bug fixes +* Fix fetching comments after fetching likes [#7167](https://github.com/diaspora/diaspora/pull/7167) +* Hide 'reshare' button on already reshared posts [#7169](https://github.com/diaspora/diaspora/pull/7169) +* Only reload profile header when changing aspect memberships [#7183](https://github.com/diaspora/diaspora/pull/7183) +* Fix visiblity on invitation modal when opening it from the stream [#7191](https://github.com/diaspora/diaspora/pull/7191) +* Add avatar fallback on tags page [#7198](https://github.com/diaspora/diaspora/pull/7198) +* Update notifications when changing the stream [#7199](https://github.com/diaspora/diaspora/pull/7199) +* Fix 500 on mobile commented and liked streams [#7219](https://github.com/diaspora/diaspora/pull/7219) + +## Features +* Show spinner when loading comments in the stream [#7170](https://github.com/diaspora/diaspora/pull/7170) +* Add a dark color theme [#7152](https://github.com/diaspora/diaspora/pull/7152) +* Added setting for custom changelog URL [#7166](https://github.com/diaspora/diaspora/pull/7166) +* Show more information of recipients on conversation creation [#7129](https://github.com/diaspora/diaspora/pull/7129) +* Update notifications every 5 minutes and when opening the notification dropdown [#6952](https://github.com/diaspora/diaspora/pull/6952) +* Show browser notifications when receiving new unread notifications [#6952](https://github.com/diaspora/diaspora/pull/6952) +* Only clear comment textarea when comment submission was successful [#7186](https://github.com/diaspora/diaspora/pull/7186) +* Add support for graceful unicorn restarts [#7217](https://github.com/diaspora/diaspora/pull/7217) + # 0.6.1.0 Note: Although this is a minor release, the configuration file changed because the old Mapbox implementation is no longer valid, and the current implementation requires additional fields. Chances are high that if you're using the old integration, it will be broken anyway. If you do use Mapbox, please check out the `diaspora.yml.example` for new parameters. diff --git a/Gemfile b/Gemfile index 5e99577d4..9e4a60e82 100644 --- a/Gemfile +++ b/Gemfile @@ -25,7 +25,6 @@ gem "json-schema", "2.7.0" gem "devise", "4.2.0" gem "devise_lastseenable", "0.0.6" -gem "devise-token_authenticatable", "0.5.2" # Captcha @@ -73,8 +72,8 @@ gem "activerecord-import", "0.15.0" # File uploading +gem "fog", "1.38.0", require: "fog/aws" gem "carrierwave", "0.11.2" -gem "fog", "1.38.0" gem "mini_magick", "4.5.1" # GUID generation @@ -105,6 +104,7 @@ source "https://rails-assets.org" do gem "rails-assets-markdown-it-sup", "1.0.0" gem "rails-assets-highlightjs", "9.7.0" gem "rails-assets-bootstrap-markdown", "2.10.0" + gem "rails-assets-corejs-typeahead", "1.0.1" # jQuery plugins @@ -136,6 +136,10 @@ gem "twitter-text", "1.14.0" gem "ruby-oembed", "0.10.1" gem "open_graph_reader", "0.6.1" +# RTL support + +gem "string-direction", "1.2.0" + # Security Headers gem "secure_headers", "3.5.0" diff --git a/Gemfile.lock b/Gemfile.lock index 0196e5d41..70ff9e4fe 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,8 +171,6 @@ GEM railties (>= 4.1.0, < 5.1) responders warden (~> 1.2.3) - devise-token_authenticatable (0.5.2) - devise (>= 4.0.0, < 4.3.0) devise_lastseenable (0.0.6) devise rails (>= 3.0.4) @@ -648,6 +646,8 @@ GEM rails-assets-jquery (>= 1.9.1, < 4) rails-assets-bootstrap-markdown (2.10.0) rails-assets-bootstrap (~> 3) + rails-assets-corejs-typeahead (1.0.1) + rails-assets-jquery (>= 1.7) rails-assets-diaspora_jsxc (0.1.5.develop.7) rails-assets-emojione (~> 2.0.1) rails-assets-favico.js (>= 0.3.10, < 0.4) @@ -821,6 +821,8 @@ GEM activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) state_machine (1.2.0) + string-direction (1.2.0) + yard (~> 0.8) swd (1.0.1) activesupport (>= 3) attr_required (>= 0.0.5) @@ -931,7 +933,6 @@ DEPENDENCIES cucumber-rails (= 1.4.5) database_cleaner (= 1.5.3) devise (= 4.2.0) - devise-token_authenticatable (= 0.5.2) devise_lastseenable (= 0.0.6) diaspora-prosody-config (= 0.0.7) diaspora_federation-rails (= 0.1.5) @@ -998,6 +999,7 @@ DEPENDENCIES rails-assets-autosize (= 3.0.17)! rails-assets-blueimp-gallery (= 2.21.3)! rails-assets-bootstrap-markdown (= 2.10.0)! + rails-assets-corejs-typeahead (= 1.0.1)! rails-assets-diaspora_jsxc (= 0.1.5.develop.7)! rails-assets-highlightjs (= 9.7.0)! rails-assets-jasmine-ajax (= 3.2.0)! @@ -1034,6 +1036,7 @@ DEPENDENCIES spring (= 2.0.0) spring-commands-cucumber (= 1.0.1) spring-commands-rspec (= 1.0.4) + string-direction (= 1.2.0) test_after_commit (= 1.1.0) timecop (= 0.8.1) turbo_dev_assets (= 0.0.2) @@ -1049,4 +1052,4 @@ DEPENDENCIES will_paginate (= 3.1.5) BUNDLED WITH - 1.13.5 + 1.13.6 diff --git a/app/assets/javascripts/app/app.js b/app/assets/javascripts/app/app.js index 1046bd66a..d95852882 100644 --- a/app/assets/javascripts/app/app.js +++ b/app/assets/javascripts/app/app.js @@ -90,6 +90,7 @@ var app = { setupHeader: function() { if(app.currentUser.authenticated()) { + app.notificationsCollection = new app.collections.Notifications(); app.header = new app.views.Header(); $("header").prepend(app.header.el); app.header.render(); @@ -114,6 +115,7 @@ var app = { // so we use Backbone.history.navigate instead. var change = Backbone.history.navigate(link.attr("href").substring(1) ,true); if(change === undefined) { Backbone.history.loadUrl(link.attr("href").substring(1)); } + app.notificationsCollection.fetch(); }); }, diff --git a/app/assets/javascripts/app/collections/notifications.js b/app/assets/javascripts/app/collections/notifications.js new file mode 100644 index 000000000..151410fe0 --- /dev/null +++ b/app/assets/javascripts/app/collections/notifications.js @@ -0,0 +1,114 @@ +app.collections.Notifications = Backbone.Collection.extend({ + model: app.models.Notification, + // URL parameter + /* eslint-disable camelcase */ + url: Routes.notifications({per_page: 10, page: 1}), + /* eslint-enable camelcase */ + page: 2, + perPage: 5, + unreadCount: 0, + unreadCountByType: {}, + timeout: 300000, // 5 minutes + + initialize: function() { + this.fetch(); + setInterval(this.pollNotifications.bind(this), this.timeout); + Diaspora.BrowserNotification.requestPermission(); + }, + + pollNotifications: function() { + var unreadCountBefore = this.unreadCount; + this.fetch(); + + this.once("finishedLoading", function() { + if (unreadCountBefore < this.unreadCount) { + Diaspora.BrowserNotification.spawnNotification( + Diaspora.I18n.t("notifications.new_notifications", {count: this.unreadCount})); + } + }, this); + }, + + fetch: function(options) { + options = options || {}; + options.remove = false; + options.merge = true; + options.parse = true; + Backbone.Collection.prototype.fetch.apply(this, [options]); + }, + + fetchMore: function() { + var hasMoreNotifications = (this.page * this.perPage) <= this.length; + // There are more notifications to load on the current page + if (hasMoreNotifications) { + this.page++; + // URL parameter + /* eslint-disable camelcase */ + var route = Routes.notifications({per_page: this.perPage, page: this.page}); + /* eslint-enable camelcase */ + this.fetch({url: route, pushBack: true}); + } + }, + + /** + * Adds new models to the collection at the end or at the beginning of the collection and + * then fires an event for each model of the collection. It will fire a different event + * based on whether the models were added at the end (typically when the scroll triggers to load more + * notifications) or at the beginning (new notifications have been added to the front of the list). + */ + set: function(items, options) { + options = options || {}; + options.at = options.pushBack ? this.length : 0; + + // Retreive back the new created models + var models = []; + var accu = function(model) { models.push(model); }; + this.on("add", accu); + Backbone.Collection.prototype.set.apply(this, [items, options]); + this.off("add", accu); + + if (options.pushBack) { + models.forEach(function(model) { this.trigger("pushBack", model); }.bind(this)); + } else { + // Fires events in the reverse order so that the first event is prepended in first position + models.reverse(); + models.forEach(function(model) { this.trigger("pushFront", model); }.bind(this)); + } + this.trigger("finishedLoading"); + }, + + parse: function(response) { + this.unreadCount = response.unread_count; + this.unreadCountByType = response.unread_count_by_type; + + return _.map(response.notification_list, function(item) { + /* eslint-disable new-cap */ + var model = new this.model(item); + /* eslint-enable new-cap */ + model.on("change:unread", this.onChangedUnreadStatus.bind(this)); + return model; + }.bind(this)); + }, + + setAllRead: function() { + this.forEach(function(model) { model.setRead(); }); + }, + + setRead: function(guid) { + this.find(function(model) { return model.guid === guid; }).setRead(); + }, + + setUnread: function(guid) { + this.find(function(model) { return model.guid === guid; }).setUnread(); + }, + + onChangedUnreadStatus: function(model) { + if (model.get("unread") === true) { + this.unreadCount++; + this.unreadCountByType[model.get("type")]++; + } else { + this.unreadCount = Math.max(this.unreadCount - 1, 0); + this.unreadCountByType[model.get("type")] = Math.max(this.unreadCountByType[model.get("type")] - 1, 0); + } + this.trigger("update"); + } +}); diff --git a/app/assets/javascripts/app/collections/reshares.js b/app/assets/javascripts/app/collections/reshares.js index 1aee51053..ab7bb9173 100644 --- a/app/assets/javascripts/app/collections/reshares.js +++ b/app/assets/javascripts/app/collections/reshares.js @@ -2,6 +2,9 @@ app.collections.Reshares = Backbone.Collection.extend({ model: app.models.Reshare, - url : "/reshares" + + initialize: function(models, options) { + this.url = "/posts/" + options.post.id + "/reshares"; + } }); // @license-end diff --git a/app/assets/javascripts/app/models/notification.js b/app/assets/javascripts/app/models/notification.js new file mode 100644 index 000000000..b2e342116 --- /dev/null +++ b/app/assets/javascripts/app/models/notification.js @@ -0,0 +1,69 @@ +app.models.Notification = Backbone.Model.extend({ + constructor: function(attributes, options) { + options = options || {}; + options.parse = true; + Backbone.Model.apply(this, [attributes, options]); + this.guid = this.get("id"); + }, + + /** + * Flattens the notification object returned by the server. + * + * The server returns an object that looks like: + * + * { + * "reshared": { + * "id": 45, + * "target_type": "Post", + * "target_id": 11, + * "recipient_id": 1, + * "unread": true, + * "created_at": "2015-10-27T19:56:30.000Z", + * "updated_at": "2015-10-27T19:56:30.000Z", + * "note_html": + * }, + * "type": "reshared" + * } + * + * The returned object looks like: + * + * { + * "type": "reshared", + * "id": 45, + * "target_type": "Post", + * "target_id": 11, + * "recipient_id": 1, + * "unread": true, + * "created_at": "2015-10-27T19:56:30.000Z", + * "updated_at": "2015-10-27T19:56:30.000Z", + * "note_html": , + * } + */ + parse: function(response) { + var result = {type: response.type}; + result = $.extend(result, response[result.type]); + return result; + }, + + setRead: function() { + this.setUnreadStatus(false); + }, + + setUnread: function() { + this.setUnreadStatus(true); + }, + + setUnreadStatus: function(state) { + if (this.get("unread") !== state) { + $.ajax({ + url: Routes.notification(this.guid), + /* eslint-disable camelcase */ + data: {set_unread: state}, + /* eslint-enable camelcase */ + type: "PUT", + context: this, + success: function() { this.set("unread", state); } + }); + } + } +}); diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js index 28d6f3a57..3615387e2 100644 --- a/app/assets/javascripts/app/models/post/interactions.js +++ b/app/assets/javascripts/app/models/post/interactions.js @@ -70,9 +70,10 @@ app.models.Post.Interactions = Backbone.Model.extend({ self.post.set({participation: true}); self.trigger("change"); self.set({"likes_count" : self.get("likes_count") + 1}); + self.likes.trigger("change"); }, - error: function() { - app.flashMessages.error(Diaspora.I18n.t("failed_to_like")); + error: function(model, response) { + app.flashMessages.handleAjaxError(response); } }); @@ -84,23 +85,26 @@ app.models.Post.Interactions = Backbone.Model.extend({ this.userLike().destroy({success : function() { self.trigger('change'); self.set({"likes_count" : self.get("likes_count") - 1}); + self.likes.trigger("change"); }}); app.instrument("track", "Unlike"); }, - comment : function (text) { + comment: function(text, options) { var self = this; + options = options || {}; - this.comments.make(text).fail(function () { - app.flashMessages.error(Diaspora.I18n.t("failed_to_comment")); + this.comments.make(text).fail(function(response) { + app.flashMessages.handleAjaxError(response); + if (options.error) { options.error(); } }).done(function() { self.post.set({participation: true}); + self.set({"comments_count": self.get("comments_count") + 1}); self.trigger('change'); //updates after sync + if (options.success) { options.success(); } }); - this.trigger("change"); //updates count in an eager manner - app.instrument("track", "Comment"); }, @@ -116,9 +120,11 @@ app.models.Post.Interactions = Backbone.Model.extend({ app.stream.addNow(reshare); } interactions.trigger("change"); + interactions.set({"reshares_count": interactions.get("reshares_count") + 1}); + interactions.reshares.trigger("change"); }) - .fail(function(){ - app.flashMessages.error(Diaspora.I18n.t("reshares.duplicate")); + .fail(function(response) { + app.flashMessages.handleAjaxError(response); }); app.instrument("track", "Reshare"); diff --git a/app/assets/javascripts/app/pages/contacts.js b/app/assets/javascripts/app/pages/contacts.js index eca20fa33..f9bd2db27 100644 --- a/app/assets/javascripts/app/pages/contacts.js +++ b/app/assets/javascripts/app/pages/contacts.js @@ -79,6 +79,9 @@ app.pages.Contacts = Backbone.View.extend({ }, showMessageModal: function(){ + $("#conversationModal").on("modal:loaded", function() { + new app.views.ConversationsForm({prefill: gon.conversationPrefill}); + }); app.helpers.showModal("#conversationModal"); }, diff --git a/app/assets/javascripts/app/pages/profile.js b/app/assets/javascripts/app/pages/profile.js index b987ea387..a2b814399 100644 --- a/app/assets/javascripts/app/pages/profile.js +++ b/app/assets/javascripts/app/pages/profile.js @@ -31,7 +31,6 @@ app.pages.Profile = app.views.Base.extend({ this.streamCollection = _.has(opts, "streamCollection") ? opts.streamCollection : null; this.streamViewClass = _.has(opts, "streamView") ? opts.streamView : null; - this.model.on("change", this.render, this); this.model.on("sync", this._done, this); // bind to global events diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js index 1884bb880..ed8ec9d9a 100644 --- a/app/assets/javascripts/app/router.js +++ b/app/assets/javascripts/app/router.js @@ -139,7 +139,7 @@ app.Router = Backbone.Router.extend({ notifications: function() { this._loadContacts(); this.renderAspectMembershipDropdowns($(document)); - new app.views.Notifications({el: "#notifications_container"}); + new app.views.Notifications({el: "#notifications_container", collection: app.notificationsCollection}); }, peopleSearch: function() { diff --git a/app/assets/javascripts/app/views/aspect_membership_view.js b/app/assets/javascripts/app/views/aspect_membership_view.js index 238349e1d..34ba8bd77 100644 --- a/app/assets/javascripts/app/views/aspect_membership_view.js +++ b/app/assets/javascripts/app/views/aspect_membership_view.js @@ -125,7 +125,7 @@ app.views.AspectMembership = app.views.Base.extend({ _displayError: function(model, resp) { this._done(); this.dropdown.closest(".aspect_membership_dropdown").removeClass("open"); // close the dropdown - app.flashMessages.error(resp.responseText); + app.flashMessages.handleAjaxError(resp); }, // remove the membership with the given id @@ -134,7 +134,7 @@ app.views.AspectMembership = app.views.Base.extend({ this.listenToOnce(membership, "sync", this._successDestroyCb); this.listenToOnce(membership, "error", this._displayError); - return membership.destroy(); + return membership.destroy({wait: true}); }, _successDestroyCb: function(aspectMembership) { diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js index 0119b3329..05ba192db 100644 --- a/app/assets/javascripts/app/views/comment_stream_view.js +++ b/app/assets/javascripts/app/views/comment_stream_view.js @@ -25,6 +25,8 @@ app.views.CommentStream = app.views.Base.extend({ postRenderTemplate : function() { this.model.comments.each(this.appendComment, this); + this.commentBox = this.$(".comment_box"); + this.commentSubmitButton = this.$("input[name='commit']"); }, presenter: function(){ @@ -38,15 +40,35 @@ app.views.CommentStream = app.views.Base.extend({ createComment: function(evt) { if(evt){ evt.preventDefault(); } - var commentText = $.trim(this.$('.comment_box').val()); - this.$(".comment_box").val(""); - this.$(".comment_box").css("height", ""); - if(commentText) { - this.model.comment(commentText); - return this; - } else { - this.$(".comment_box").focus(); + var commentText = $.trim(this.commentBox.val()); + if (commentText === "") { + this.commentBox.focus(); + return; } + + this.disableCommentBox(); + + this.model.comment(commentText, { + success: function() { + this.commentBox.val(""); + this.enableCommentBox(); + autosize.update(this.commentBox); + }.bind(this), + error: function() { + this.enableCommentBox(); + this.commentBox.focus(); + }.bind(this) + }); + }, + + disableCommentBox: function() { + this.commentBox.prop("disabled", true); + this.commentSubmitButton.prop("disabled", true); + }, + + enableCommentBox: function() { + this.commentBox.removeAttr("disabled"); + this.commentSubmitButton.removeAttr("disabled"); }, keyDownOnCommentBox: function(evt) { @@ -104,10 +126,12 @@ app.views.CommentStream = app.views.Base.extend({ }, expandComments: function(evt){ + this.$(".loading-comments").removeClass("hidden"); if(evt){ evt.preventDefault(); } this.model.comments.fetch({ success: function() { this.$("div.comment.show_comments").addClass("hidden"); + this.$(".loading-comments").addClass("hidden"); }.bind(this) }); } diff --git a/app/assets/javascripts/app/views/conversations_form_view.js b/app/assets/javascripts/app/views/conversations_form_view.js index bfdfe62fb..74f848de3 100644 --- a/app/assets/javascripts/app/views/conversations_form_view.js +++ b/app/assets/javascripts/app/views/conversations_form_view.js @@ -5,40 +5,83 @@ app.views.ConversationsForm = Backbone.View.extend({ events: { "keydown .conversation-message-text": "keyDown", + "click .conversation-recipient-tag .remove": "removeRecipient" }, initialize: function(opts) { - this.contacts = _.has(opts, "contacts") ? opts.contacts : null; - this.prefill = []; - if (_.has(opts, "prefillName") && _.has(opts, "prefillValue")) { - this.prefill = [{name: opts.prefillName, value: opts.prefillValue}]; + opts = opts || {}; + this.conversationRecipients = []; + + this.typeaheadElement = this.$el.find("#contacts-search-input"); + this.contactsIdsListInput = this.$el.find("#contact-ids"); + this.tagListElement = this.$("#recipients-tag-list"); + + this.search = new app.views.SearchBase({ + el: this.$el.find("#new-conversation"), + typeaheadInput: this.typeaheadElement, + customSearch: true, + autoselect: true, + remoteRoute: {url: "/contacts", extraParameters: "mutual=true"} + }); + + this.bindTypeaheadEvents(); + + this.tagListElement.empty(); + if (opts.prefill) { + this.prefill(opts.prefill); } - this.prepareAutocomplete(this.contacts); + this.$("form#new-conversation").on("ajax:success", this.conversationCreateSuccess); this.$("form#new-conversation").on("ajax:error", this.conversationCreateError); }, - prepareAutocomplete: function(data){ - this.$("#contact-autocomplete").autoSuggest(data, { - selectedItemProp: "name", - searchObjProps: "name", - asHtmlID: "contact_ids", - retrieveLimit: 10, - minChars: 1, - keyDelay: 0, - startText: '', - emptyText: Diaspora.I18n.t("no_results"), - preFill: this.prefill - }); - $("#contact_ids").attr("aria-labelledby", "toLabel").focus(); + addRecipient: function(person) { + this.conversationRecipients.push(person); + this.updateContactIdsListInput(); + /* eslint-disable camelcase */ + this.tagListElement.append(HandlebarsTemplates.conversation_recipient_tag_tpl(person)); + /* eslint-enable camelcase */ }, - keyDown : function(evt) { - if(evt.which === Keycodes.ENTER && evt.ctrlKey) { + prefill: function(handles) { + handles.forEach(this.addRecipient.bind(this)); + }, + + updateContactIdsListInput: function() { + this.contactsIdsListInput.val(_(this.conversationRecipients).pluck("id").join(",")); + this.search.ignoreDiasporaIds.length = 0; + this.conversationRecipients.forEach(this.search.ignorePersonForSuggestions.bind(this.search)); + }, + + bindTypeaheadEvents: function() { + this.typeaheadElement.on("typeahead:select", function(evt, person) { + this.onSuggestionSelection(person); + }.bind(this)); + }, + + onSuggestionSelection: function(person) { + this.addRecipient(person); + this.typeaheadElement.typeahead("val", ""); + }, + + keyDown: function(evt) { + if (evt.which === Keycodes.ENTER && evt.ctrlKey) { $(evt.target).parents("form").submit(); } }, + removeRecipient: function(evt) { + var $recipientTagEl = $(evt.target).parents(".conversation-recipient-tag"); + var diasporaHandle = $recipientTagEl.data("diaspora-handle"); + + this.conversationRecipients = this.conversationRecipients.filter(function(person) { + return diasporaHandle !== person.handle; + }); + + this.updateContactIdsListInput(); + $recipientTagEl.remove(); + }, + conversationCreateSuccess: function(evt, data) { app._changeLocation(Routes.conversation(data.id)); }, diff --git a/app/assets/javascripts/app/views/conversations_inbox_view.js b/app/assets/javascripts/app/views/conversations_inbox_view.js index 97e31f5c3..4e301a8a0 100644 --- a/app/assets/javascripts/app/views/conversations_inbox_view.js +++ b/app/assets/javascripts/app/views/conversations_inbox_view.js @@ -9,7 +9,7 @@ app.views.ConversationsInbox = Backbone.View.extend({ }, initialize: function() { - new app.views.ConversationsForm({contacts: gon.contacts}); + new app.views.ConversationsForm(); this.setupConversation(); }, diff --git a/app/assets/javascripts/app/views/flash_messages_view.js b/app/assets/javascripts/app/views/flash_messages_view.js index cb5b214b2..b5c2286d6 100644 --- a/app/assets/javascripts/app/views/flash_messages_view.js +++ b/app/assets/javascripts/app/views/flash_messages_view.js @@ -16,5 +16,13 @@ app.views.FlashMessages = app.views.Base.extend({ error: function(message){ this._flash(message, true); + }, + + handleAjaxError: function(response) { + if (response.status === 0) { + this.error(Diaspora.I18n.t("errors.connection")); + } else { + this.error(response.responseText); + } } }); diff --git a/app/assets/javascripts/app/views/header_view.js b/app/assets/javascripts/app/views/header_view.js index 5b682c3b3..496cd83d3 100644 --- a/app/assets/javascripts/app/views/header_view.js +++ b/app/assets/javascripts/app/views/header_view.js @@ -12,12 +12,12 @@ app.views.Header = app.views.Base.extend({ }); }, - postRenderTemplate: function(){ - new app.views.Notifications({ el: "#notification-dropdown" }); - this.notificationDropdown = new app.views.NotificationDropdown({ el: "#notification-dropdown" }); - new app.views.Search({ el: "#header-search-form" }); + postRenderTemplate: function() { + new app.views.Notifications({el: "#notification-dropdown", collection: app.notificationsCollection}); + new app.views.NotificationDropdown({el: "#notification-dropdown", collection: app.notificationsCollection}); + new app.views.Search({el: "#header-search-form"}); }, - menuElement: function(){ return this.$("ul.dropdown"); }, + menuElement: function() { return this.$("ul.dropdown"); } }); // @license-end diff --git a/app/assets/javascripts/app/views/likes_info_view.js b/app/assets/javascripts/app/views/likes_info_view.js index 9300ac9ad..d511c2ef9 100644 --- a/app/assets/javascripts/app/views/likes_info_view.js +++ b/app/assets/javascripts/app/views/likes_info_view.js @@ -11,7 +11,7 @@ app.views.LikesInfo = app.views.Base.extend({ tooltipSelector : ".avatar", initialize : function() { - this.model.interactions.bind('change', this.render, this); + this.model.interactions.likes.on("change", this.render, this); this.displayAvatars = false; }, @@ -19,18 +19,16 @@ app.views.LikesInfo = app.views.Base.extend({ return _.extend(this.defaultPresenter(), { likes : this.model.interactions.likes.toJSON(), likesCount : this.model.interactions.likesCount(), - displayAvatars : this.model.interactions.get("fetched") && this.displayAvatars + displayAvatars: this.displayAvatars }); }, showAvatars : function(evt){ if(evt) { evt.preventDefault() } this.displayAvatars = true; - if(!this.model.interactions.get("fetched")){ - this.model.interactions.fetch(); - } else { - this.model.interactions.trigger("change"); - } + this.model.interactions.likes.fetch({success: function() { + this.model.interactions.likes.trigger("change"); + }.bind(this)}); } }); // @license-end diff --git a/app/assets/javascripts/app/views/notification_dropdown_view.js b/app/assets/javascripts/app/views/notification_dropdown_view.js index a44556c9a..a72f1e8f1 100644 --- a/app/assets/javascripts/app/views/notification_dropdown_view.js +++ b/app/assets/javascripts/app/views/notification_dropdown_view.js @@ -6,16 +6,21 @@ app.views.NotificationDropdown = app.views.Base.extend({ }, initialize: function(){ - $(document.body).click($.proxy(this.hideDropdown, this)); + $(document.body).click(this.hideDropdown.bind(this)); - this.notifications = []; - this.perPage = 5; - this.hasMoreNotifs = true; this.badge = this.$el; this.dropdown = $("#notification-dropdown"); this.dropdownNotifications = this.dropdown.find(".notifications"); this.ajaxLoader = this.dropdown.find(".ajax-loader"); this.perfectScrollbarInitialized = false; + this.dropdownNotifications.scroll(this.dropdownScroll.bind(this)); + this.bindCollectionEvents(); + }, + + bindCollectionEvents: function() { + this.collection.on("pushFront", this.onPushFront.bind(this)); + this.collection.on("pushBack", this.onPushBack.bind(this)); + this.collection.on("finishedLoading", this.finishLoading.bind(this)); }, toggleDropdown: function(evt){ @@ -31,12 +36,11 @@ app.views.NotificationDropdown = app.views.Base.extend({ }, showDropdown: function(){ - this.resetParams(); this.ajaxLoader.show(); this.dropdown.addClass("dropdown-open"); this.updateScrollbar(); this.dropdownNotifications.addClass("loading"); - this.getNotifications(); + this.collection.fetch(); }, hideDropdown: function(evt){ @@ -50,40 +54,18 @@ app.views.NotificationDropdown = app.views.Base.extend({ dropdownScroll: function(){ var isLoading = ($(".loading").length === 1); - if (this.isBottom() && this.hasMoreNotifs && !isLoading){ + if (this.isBottom() && !isLoading) { this.dropdownNotifications.addClass("loading"); - this.getNotifications(); + this.collection.fetchMore(); } }, - getParams: function(){ - if(this.notifications.length === 0){ return{ per_page: 10, page: 1 }; } - else{ return{ per_page: this.perPage, page: this.nextPage }; } - }, - - resetParams: function(){ - this.notifications.length = 0; - this.hasMoreNotifs = true; - delete this.nextPage; - }, - isBottom: function(){ var bottom = this.dropdownNotifications.prop("scrollHeight") - this.dropdownNotifications.height(); var currentPosition = this.dropdownNotifications.scrollTop(); return currentPosition + 50 >= bottom; }, - getNotifications: function(){ - var self = this; - $.getJSON(Routes.notifications(this.getParams()), function(notifications){ - $.each(notifications, function(){ self.notifications.push(this); }); - self.hasMoreNotifs = notifications.length >= self.perPage; - if(self.nextPage){ self.nextPage++; } - else { self.nextPage = 3; } - self.renderNotifications(); - }); - }, - hideAjaxLoader: function(){ var self = this; this.ajaxLoader.find(".spinner").fadeTo(200, 0, function(){ @@ -93,28 +75,23 @@ app.views.NotificationDropdown = app.views.Base.extend({ }); }, - renderNotifications: function(){ - var self = this; - this.dropdownNotifications.find(".media.stream-element").remove(); - $.each(self.notifications, function(index, notifications){ - $.each(notifications, function(index, notification){ - if($.inArray(notification, notifications) === -1){ - var node = self.dropdownNotifications.append(notification.note_html); - $(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip(); - $(node).find(self.avatars.selector).error(self.avatars.fallback); - } - }); - }); + onPushBack: function(notification) { + var node = this.dropdownNotifications.append(notification.get("note_html")); + $(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip(); + $(node).find(this.avatars.selector).error(this.avatars.fallback); + }, - this.hideAjaxLoader(); + onPushFront: function(notification) { + var node = this.dropdownNotifications.prepend(notification.get("note_html")); + $(node).find(".unread-toggle .entypo-eye").tooltip("destroy").tooltip(); + $(node).find(this.avatars.selector).error(this.avatars.fallback); + }, + finishLoading: function() { app.helpers.timeago(this.dropdownNotifications); - this.updateScrollbar(); + this.hideAjaxLoader(); this.dropdownNotifications.removeClass("loading"); - this.dropdownNotifications.scroll(function(){ - self.dropdownScroll(); - }); }, updateScrollbar: function() { diff --git a/app/assets/javascripts/app/views/notifications_view.js b/app/assets/javascripts/app/views/notifications_view.js index 08400742e..3ae156348 100644 --- a/app/assets/javascripts/app/views/notifications_view.js +++ b/app/assets/javascripts/app/views/notifications_view.js @@ -1,96 +1,85 @@ // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later app.views.Notifications = Backbone.View.extend({ - events: { - "click .unread-toggle" : "toggleUnread", - "click #mark_all_read_link": "markAllRead" + "click .unread-toggle": "toggleUnread", + "click #mark-all-read-link": "markAllRead" }, initialize: function() { $(".unread-toggle .entypo-eye").tooltip(); app.helpers.timeago($(document)); + this.bindCollectionEvents(); + }, + + bindCollectionEvents: function() { + this.collection.on("change", this.onChangedUnreadStatus.bind(this)); + this.collection.on("update", this.updateView.bind(this)); }, toggleUnread: function(evt) { var note = $(evt.target).closest(".stream-element"); var unread = note.hasClass("unread"); var guid = note.data("guid"); - if (unread){ this.setRead(guid); } - else { this.setUnread(guid); } - }, - - getAllUnread: function() { return $(".media.stream-element.unread"); }, - - setRead: function(guid) { this.setUnreadStatus(guid, false); }, - - setUnread: function(guid){ this.setUnreadStatus(guid, true); }, - - setUnreadStatus: function(guid, state){ - $.ajax({ - url: "/notifications/" + guid, - data: { set_unread: state }, - type: "PUT", - context: this, - success: this.clickSuccess - }); - }, - - clickSuccess: function(data) { - var guid = data.guid; - var type = $(".stream-element[data-guid=" + guid + "]").data("type"); - this.updateView(guid, type, data.unread); - }, - - markAllRead: function(evt){ - if(evt) { evt.preventDefault(); } - var self = this; - this.getAllUnread().each(function(i, el){ - self.setRead($(el).data("guid")); - }); - }, - - updateView: function(guid, type, unread) { - var change = unread ? 1 : -1, - allNotes = $("#notifications_container .list-group > a:eq(0) .badge"), - typeNotes = $("#notifications_container .list-group > a[data-type=" + type + "] .badge"), - headerBadge = $(".notifications-link .badge"), - note = $(".notifications .stream-element[data-guid=" + guid + "]"), - markAllReadLink = $("a#mark_all_read_link"), - translationKey = unread ? "notifications.mark_read" : "notifications.mark_unread"; - - if(unread){ note.removeClass("read").addClass("unread"); } - else { note.removeClass("unread").addClass("read"); } - - $(".unread-toggle .entypo-eye", note) - .tooltip("destroy") - .removeAttr("data-original-title") - .attr("title",Diaspora.I18n.t(translationKey)) - .tooltip(); - - [allNotes, typeNotes, headerBadge].forEach(function(element){ - element.text(function(i, text){ - return parseInt(text) + change; - }); - }); - - [allNotes, typeNotes].forEach(function(badge) { - if(badge.text() > 0) { - badge.removeClass("hidden"); - } - else { - badge.addClass("hidden"); - } - }); - - if(headerBadge.text() > 0){ - headerBadge.removeClass("hidden"); - markAllReadLink.removeClass("disabled"); + if (unread) { + this.collection.setRead(guid); + } else { + this.collection.setUnread(guid); } - else{ - headerBadge.addClass("hidden"); + }, + + markAllRead: function() { + this.collection.setAllRead(); + }, + + onChangedUnreadStatus: function(model) { + var unread = model.get("unread"); + var translationKey = unread ? "notifications.mark_read" : "notifications.mark_unread"; + var note = $(".stream-element[data-guid=" + model.guid + "]"); + + note.find(".entypo-eye") + .tooltip("destroy") + .removeAttr("data-original-title") + .attr("title", Diaspora.I18n.t(translationKey)) + .tooltip(); + + if (unread) { + note.removeClass("read").addClass("unread"); + } else { + note.removeClass("unread").addClass("read"); + } + }, + + updateView: function() { + var notificationsContainer = $("#notifications_container"); + + // update notification counts in the sidebar + Object.keys(this.collection.unreadCountByType).forEach(function(notificationType) { + var count = this.collection.unreadCountByType[notificationType]; + this.updateBadge(notificationsContainer.find("a[data-type=" + notificationType + "] .badge"), count); + }.bind(this)); + + this.updateBadge(notificationsContainer.find("a[data-type=all] .badge"), this.collection.unreadCount); + + // update notification count in the header + this.updateBadge($(".notifications-link .badge"), this.collection.unreadCount); + + var markAllReadLink = $("a#mark-all-read-link"); + + if (this.collection.unreadCount > 0) { + markAllReadLink.removeClass("disabled"); + } else { markAllReadLink.addClass("disabled"); } + }, + + updateBadge: function(badge, count) { + badge.text(count); + if (count > 0) { + badge.removeClass("hidden"); + } else { + badge.addClass("hidden"); + } } }); // @license-end diff --git a/app/assets/javascripts/app/views/profile_header_view.js b/app/assets/javascripts/app/views/profile_header_view.js index 906736895..1522b71e4 100644 --- a/app/assets/javascripts/app/views/profile_header_view.js +++ b/app/assets/javascripts/app/views/profile_header_view.js @@ -15,6 +15,7 @@ app.views.ProfileHeader = app.views.Base.extend({ initialize: function(opts) { this.photos = _.has(opts, 'photos') ? opts.photos : null; this.contacts = _.has(opts, 'contacts') ? opts.contacts : null; + this.model.on("change", this.render, this); $("#mentionModal").on("modal:loaded", this.mentionModalLoaded.bind(this)); $("#mentionModal").on("hidden.bs.modal", this.mentionModalHidden); }, @@ -79,8 +80,11 @@ app.views.ProfileHeader = app.views.Base.extend({ }, showMessageModal: function(){ + $("#conversationModal").on("modal:loaded", function() { + new app.views.ConversationsForm({prefill: gon.conversationPrefill}); + }); app.helpers.showModal("#conversationModal"); - }, + } }); // @license-end diff --git a/app/assets/javascripts/app/views/publisher/mention_view.js b/app/assets/javascripts/app/views/publisher/mention_view.js index 75c0015ea..86b3b07aa 100644 --- a/app/assets/javascripts/app/views/publisher/mention_view.js +++ b/app/assets/javascripts/app/views/publisher/mention_view.js @@ -32,7 +32,7 @@ app.views.PublisherMention = app.views.SearchBase.extend({ typeaheadInput: this.typeaheadInput, customSearch: true, autoselect: true, - remoteRoute: "/contacts" + remoteRoute: {url: "/contacts"} }); }, diff --git a/app/assets/javascripts/app/views/reshares_info_view.js b/app/assets/javascripts/app/views/reshares_info_view.js index b91027e84..a1d985dd4 100644 --- a/app/assets/javascripts/app/views/reshares_info_view.js +++ b/app/assets/javascripts/app/views/reshares_info_view.js @@ -11,7 +11,7 @@ app.views.ResharesInfo = app.views.Base.extend({ tooltipSelector : ".avatar", initialize : function() { - this.model.interactions.bind("change", this.render, this); + this.model.interactions.reshares.bind("change", this.render, this); this.displayAvatars = false; }, @@ -19,18 +19,16 @@ app.views.ResharesInfo = app.views.Base.extend({ return _.extend(this.defaultPresenter(), { reshares : this.model.interactions.reshares.toJSON(), resharesCount : this.model.interactions.resharesCount(), - displayAvatars : this.model.interactions.get("fetched") && this.displayAvatars + displayAvatars: this.displayAvatars }); }, showAvatars : function(evt){ if(evt) { evt.preventDefault() } this.displayAvatars = true; - if(!this.model.interactions.get("fetched")){ - this.model.interactions.fetch(); - } else { - this.model.interactions.trigger("change"); - } + this.model.interactions.reshares.fetch({success: function() { + this.model.interactions.reshares.trigger("change"); + }.bind(this)}); } }); // @license-end diff --git a/app/assets/javascripts/app/views/search_base_view.js b/app/assets/javascripts/app/views/search_base_view.js index 44277b851..eb00aaeaa 100644 --- a/app/assets/javascripts/app/views/search_base_view.js +++ b/app/assets/javascripts/app/views/search_base_view.js @@ -28,9 +28,13 @@ app.views.SearchBase = app.views.Base.extend({ }; // Allow bloodhound to look for remote results if there is a route given in the options - if(options.remoteRoute) { + if (options.remoteRoute && options.remoteRoute.url) { + var extraParameters = ""; + if (options.remoteRoute.extraParameters) { + extraParameters += "&" + options.remoteRoute.extraParameters; + } bloodhoundOptions.remote = { - url: options.remoteRoute + ".json?q=%QUERY", + url: options.remoteRoute.url + ".json?q=%QUERY" + extraParameters, wildcard: "%QUERY", transform: this.transformBloodhoundResponse.bind(this) }; diff --git a/app/assets/javascripts/app/views/search_view.js b/app/assets/javascripts/app/views/search_view.js index b2486659b..c0d8ec749 100644 --- a/app/assets/javascripts/app/views/search_view.js +++ b/app/assets/javascripts/app/views/search_view.js @@ -10,7 +10,7 @@ app.views.Search = app.views.SearchBase.extend({ this.searchInput = this.$("#q"); app.views.SearchBase.prototype.initialize.call(this, { typeaheadInput: this.searchInput, - remoteRoute: this.$el.attr("action"), + remoteRoute: {url: this.$el.attr("action")}, suggestionLink: true }); this.searchInput.on("typeahead:select", this.suggestionSelected); diff --git a/app/assets/javascripts/app/views/tags_view.js b/app/assets/javascripts/app/views/tags_view.js index 3913f8798..9b70df1e6 100644 --- a/app/assets/javascripts/app/views/tags_view.js +++ b/app/assets/javascripts/app/views/tags_view.js @@ -5,6 +5,8 @@ app.views.Tags = Backbone.View.extend({ if(app.publisher) { app.publisher.setText("#"+ opts.hashtagName + " "); } + // add avatar fallback if it can't be loaded + $(app.views.Base.prototype.avatars.selector).error(app.views.Base.prototype.avatars.fallback); } }); // @license-end diff --git a/app/assets/javascripts/helpers/browser_notification.js b/app/assets/javascripts/helpers/browser_notification.js new file mode 100644 index 000000000..e8c8b7d8f --- /dev/null +++ b/app/assets/javascripts/helpers/browser_notification.js @@ -0,0 +1,22 @@ +Diaspora.BrowserNotification = { + requestPermission: function() { + if ("Notification" in window && Notification.permission !== "granted" && Notification.permission !== "denied") { + Notification.requestPermission(); + } + }, + + spawnNotification: function(title, summary) { + if ("Notification" in window && Notification.permission === "granted") { + if (!_.isString(title)) { + throw new Error("No notification title given."); + } + + summary = summary || ""; + + new Notification(title, { + body: summary, + icon: ImagePaths.get("branding/logos/asterisk_white_mobile.png") + }); + } + } +}; diff --git a/app/assets/javascripts/helpers/i18n.js b/app/assets/javascripts/helpers/i18n.js index 42bd7a886..e6db0f2e1 100644 --- a/app/assets/javascripts/helpers/i18n.js +++ b/app/assets/javascripts/helpers/i18n.js @@ -18,7 +18,7 @@ Diaspora.I18n = { }, updateLocale: function(locale, data) { - locale.data = $.extend(locale.data, data); + locale.data = $.extend({}, locale.data, data); var rule = locale.data.pluralization_rule; if (typeof rule !== "undefined") { diff --git a/app/assets/javascripts/jsxc.js b/app/assets/javascripts/jsxc.js index 9209fd7bf..9e90634ca 100644 --- a/app/assets/javascripts/jsxc.js +++ b/app/assets/javascripts/jsxc.js @@ -12,7 +12,7 @@ // initialize jsxc xmpp client $(document).ready(function() { if (app.currentUser.authenticated()) { - $.post('api/v1/tokens', null, function(data) { + $.post("/user/auth_token", null, function(data) { if (jsxc && data['token']) { var jid = app.currentUser.get('diaspora_id'); jsxc.init({ diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 1d1390820..36541f536 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -30,7 +30,7 @@ //= require markdown-it-sup //= require highlightjs //= require clear-form -//= require typeahead.bundle.js +//= require corejs-typeahead //= require app/app //= require diaspora //= require_tree ./helpers diff --git a/app/assets/javascripts/mobile/mobile_post_actions.js b/app/assets/javascripts/mobile/mobile_post_actions.js index 6f7c18ee6..56df0e533 100644 --- a/app/assets/javascripts/mobile/mobile_post_actions.js +++ b/app/assets/javascripts/mobile/mobile_post_actions.js @@ -98,8 +98,12 @@ success: function() { Diaspora.Mobile.PostActions.toggleActive(link); }, - error: function() { - alert(Diaspora.I18n.t("failed_to_reshare")); + error: function(response) { + if (response.status === 0) { + alert(Diaspora.I18n.t("errors.connection")); + } else { + alert(response.responseText); + } }, complete: function() { Diaspora.Mobile.PostActions.hideLoader(link); diff --git a/app/assets/stylesheets/bootstrap-variables.scss b/app/assets/stylesheets/bootstrap-variables.scss index bca512cff..c8d8f634c 100644 --- a/app/assets/stylesheets/bootstrap-variables.scss +++ b/app/assets/stylesheets/bootstrap-variables.scss @@ -187,9 +187,9 @@ $btn-success-color: #333 !default; // $input-bg-disabled: $gray-lighter //** Text color for ``s -// $input-color: $gray +$input-color: $text-dark-grey !default; //** `` border color -// $input-border: #ccc +$input-border: $border-grey !default; // TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4 //** Default `.form-control` border radius @@ -202,6 +202,7 @@ $btn-success-color: #333 !default; //** Border color for inputs on focus // $input-border-focus: #66afe9 +$input-border-focus: $input-border !default; //** Placeholder text color // $input-color-placeholder: #999 @@ -668,7 +669,7 @@ $navbar-collapse-max-height: 480px; // //## //** Background color on `.list-group-item` -$list-group-bg: $white; +$list-group-bg: $white !default; //** `.list-group-item` border color $list-group-border: transparent; //** List group border radius diff --git a/app/assets/stylesheets/color-variables.scss b/app/assets/stylesheets/color-variables.scss index d3862a09d..40acec470 100644 --- a/app/assets/stylesheets/color-variables.scss +++ b/app/assets/stylesheets/color-variables.scss @@ -3,31 +3,32 @@ $black: #000; $text-grey: #999; $text-dark-grey: #666; -$text: #333; +$text-color-pale: $text-grey !default; +$text-color-active: $black !default; -$background-white: $white; -$background-grey: #eee; -$background-blue: #e7f2f7; +$background-grey: #eee !default; +$background-blue: #e7f2f7 !default; $grey: #2b2b2b; $medium-gray: #ccc; $light-grey: #ddd; -$border-grey: $light-grey; -$border-medium-grey: $medium-gray; -$border-dark-grey: $text-grey; -$border-medium-grey: #ccc; +$border-grey: $light-grey !default; +$border-medium-grey: $medium-gray !default; +$border-dark-grey: $text-grey !default; $link-grey: #777; -$link-disabled-grey: $text-grey; -$green: #8ede3d; +$icon-color: $black !default; + +$green: #8ede3d !default; $light-green: lighten($green, 20%); -$red: #a80000; -$blue: #3f8fba; +$red: #a80000 !default; +$blue: #3f8fba !default; -$main-background: #f0f0f0 !default; -$sidebars-background: $background-white !default; -$left-navbar-drawer-background: darken($sidebars-background, 6%); +$main-background: darken($white, 6%) !default; +$framed-background: $white !default; +$left-navbar-drawer-background: darken($white, 6%) !default; +$hovercard-background: $white !default; $card-shadow: 0 1px 2px 0 rgba(0, 0, 0, .16), 0 2px 10px 0 rgba(0, 0, 0, .12) !default; diff --git a/app/assets/stylesheets/color_themes/_color_theme_override_dark.scss b/app/assets/stylesheets/color_themes/_color_theme_override_dark.scss new file mode 100644 index 000000000..1719460f9 --- /dev/null +++ b/app/assets/stylesheets/color_themes/_color_theme_override_dark.scss @@ -0,0 +1,170 @@ +// Only overriding existing selectors here, so disable some lint rules +// scss-lint:disable IdSelector, SelectorFormat, NestingDepth, SelectorDepth, QualifyingElement +body { + .navbar.navbar-fixed-top #user_menu .dropdown-menu > li > a { + color: $text-color; + &:hover { color: $white; } + } + + .publisher { + .mentions-input-box { background-color: $gray; } + form { + #publisher_textarea_wrapper { background-color: $gray; } + .btn.btn-link.question_mark:hover .entypo-cog { color: $gray-light; } + } + + .write-preview-tabs > li.active * { color: $text-color; } + .md-preview { background-color: $gray; } + .md-cancel:hover .entypo-cross { color: $gray-light; } + .publisher-buttonbar .btn.btn-link:hover i { color: $gray-light; } + } + + .aspect_dropdown li a .text { color: $dropdown-link-color; } + + .info .tag { background-color: $gray-light; } + + .poll_form .progress { + background-color: $gray-dark; + .bar { background-color: $gray-light; } + } + + .stream-element .collapsible { + .markdown-content hr { border-top: 1px solid $hr-border; } + .expander { + @include linear-gradient(transparent, $gray-light, 0%, 95%); + border-bottom: 2px solid $gray-light; + color: $text-color; + text-shadow: 0 0 7px $black; + } + } + + code, + pre { + background-color: $gray-dark; + border: 1px solid $border-medium-grey; + color: $text-color; + } + + pre code { border: 0; } + + @import 'highlightjs/darcula'; + + #single-post-content .head { + #post-info .author { color: lighten($gray-lighter, 27%); } + #single-post-actions i.entypo-heart.red:hover { color: $red; } + } + + .opengraph a { color: lighten($gray-lighter, 27%); } + + .tag:hover { background-color: desaturate(darken($blue, 35%), 20%); } + + #profile_container .profile_header { + #author_info #sharing_message.entypo-check { color: lighten($green, 10%); } + } + + #invitationsModal #email_invitation { border-top: 1px dashed $gray-light; } + + #contacts_container #people_stream.contacts .stream-element.in_aspect { + background-color: $state-success-bg; + border-left: 3px solid darken($state-success-bg, 10%); + } + + .left-navbar #tags_list { + .as-list { + color: $text-color; + + em { + background-color: lighten($background-blue, 10%); + color: $text-color; + } + } + + .as-result-item.active { color: $text-color; } + } + + #faq .question { + background-color: $gray-dark; + a.toggle { color: $gray-lighter; } + &.collapsed { border: 2px solid $gray-dark; } + &.opened { + border: 2px solid darken($green, 10%); + h4 { background-color: darken($green, 10%); } + } + + .answer { background-color: $gray; } + } + + #welcome-to-diaspora { background: $orange; } + + .block-form fieldset .form-control:focus { border-color: $input-border; } + + &.page-registrations.action-new, + &.page-registrations.action-create { + .ball { filter: invert(100%); } + } + + .spinner { border-color: $gray-light transparent $gray-light $gray-light; } + + // AutoSuggest CSS + ul.as-selections { + background-color: $framed-background; + + li.as-selection-item, + li.as-selection-item.blur { + background-color: $gray-dark; + border: 1px solid $gray-darker; + box-shadow: 0 1px 1px $gray-darker; + color: $text-color; + text-shadow: 0 1px 1px $gray-darker; + } + + li.as-selection-item a.as-close, + li.as-selection-item.blur a.as-close { + color: $text-color; + text-shadow: 0 1px 1px $gray-darker; + } + + li:hover.as-selection-item { + background-color: $light-blue; + border-color: $brand-primary; + color: $white; + a.as-close { color: $gray-light; } + } + + li.as-selection-item.selected { border-color: $brand-primary; } + li.as-selection-item a:hover.as-close { color: $white; } + li.as-selection-item a:active.as-close { color: $gray-lighter; } + } + + ul.as-list { + background-color: $gray-dark; + box-shadow: 0 2px 12px $gray-light; + color: $text-color; + } + + li.as-result-item, + li.as-message { + border: 1px solid $gray-dark; + } + + li.as-result-item.active { + background-color: $brand-primary; + border-color: $brand-primary; + text-shadow: none; + + em { background: darken($brand-primary, 10%); } + } + // End AutoSuggest CSS + + // Bootstrap Switch CSS + .bootstrap-switch { + border-color: $border-grey; + .bootstrap-switch-label { background: $framed-background; } + .bootstrap-switch-handle-on.bootstrap-switch-default, + .bootstrap-switch-handle-off.bootstrap-switch-default { + background: $gray-dark; + color: $text-color; + } + } + // End Bootstrap Switch CSS +} diff --git a/app/assets/stylesheets/color_themes/_color_theme_override_origwhite.scss b/app/assets/stylesheets/color_themes/_color_theme_override_origwhite.scss index c8e7fe62f..1d218888a 100644 --- a/app/assets/stylesheets/color_themes/_color_theme_override_origwhite.scss +++ b/app/assets/stylesheets/color_themes/_color_theme_override_origwhite.scss @@ -17,10 +17,4 @@ body { .left-navbar { border-right: 1px solid $border-grey; } - - .right-sidebar-fixed-background, - .right-sidebar-fixed-background, - .rightbar { - border-left: 1px solid $sidebars-background; - } } diff --git a/app/assets/stylesheets/color_themes/dark/_style.scss b/app/assets/stylesheets/color_themes/dark/_style.scss new file mode 100644 index 000000000..1078d86bc --- /dev/null +++ b/app/assets/stylesheets/color_themes/dark/_style.scss @@ -0,0 +1,153 @@ +// Main color(s) +$white: #fff; +$black: #000; + +$gray-base: $black; +$gray-darker: lighten($gray-base, 6%); +$gray-dark: lighten($gray-base, 9.5%); +$gray: lighten($gray-base, 13.5%); +$gray-light: lighten($gray-base, 28%); +$gray-lighter: lighten($gray-base, 58%); + +$green: #346535; +$red: #622; +$blue: #4183c4; +$yellow: #645a1b; +$orange: #664100; + +$light-blue: lighten($blue, 5%); + +$brand-primary: darken($blue, 5%); +$brand-success: $green; +$brand-info: darken(adjust-hue($brand-primary, -30), 15%); +$brand-danger: lighten($red, 10%); + +// Bootstrap Variables +//== Scaffolding +$body-bg: $gray; +$text-color: lighten($gray-lighter, 17%); +$link-color: $blue; + +//== Tables +$table-bg-accent: $gray-dark; +$table-border-color: $gray-light; + +//== Buttons +$btn-default-color: $gray-lighter; +$btn-default-bg: $gray-light; +$btn-default-border: $gray-darker; + +$btn-success-color: $white; + +//== Forms +$input-bg: $gray-dark; + +$input-color: $text-color; +$input-border: $gray-light; +$input-border-focus: $brand-primary; + +$input-color-placeholder: lighten($gray-light, 7%); + +$legend-color: $text-color; +$legend-border-color: $gray-light; + +//== Dropdowns +$dropdown-bg: lighten($gray-base, 15%); +$dropdown-divider-bg: $gray-darker; +$dropdown-link-color: $text-color; +$dropdown-link-hover-color: $dropdown-link-color; + +//== Navbar +$navbar-inverse-bg: $gray-darker; +$navbar-inverse-link-hover-color: $text-color; +$navbar-inverse-brand-hover-color: $navbar-inverse-link-hover-color; + +//== Tabs +$nav-tabs-active-link-hover-bg: $gray; +$nav-tabs-active-link-hover-border-color: $gray-darker; + +//== Navs +$nav-link-hover-bg: $gray-darker; + +//== Pagination +$pagination-color: $light-blue; +$pagination-bg: $gray-light; +$pagination-border: $gray-darker; + +$pagination-hover-color: $gray-dark; +$pagination-hover-bg: $light-blue; +$pagination-hover-border: $pagination-border; + +$pagination-active-border: $pagination-border; + +$pagination-disabled-color: $gray-dark; +$pagination-disabled-bg: $gray-light; +$pagination-disabled-border: $pagination-border; + +//== Form states and alerts +$state-success-text: lighten($green, 30%); +$state-success-bg: darken($green, 10%); +$state-success-border: darken($state-success-bg, 20%); + +$state-info-text: lighten($blue, 20%); +$state-info-bg: darken($blue, 20%); +$state-info-border: darken($state-info-bg, 20%); + +$state-warning-text: lighten($yellow, 30%); +$state-warning-bg: $yellow; +$state-warning-border: darken($state-warning-bg, 20%); + +$state-danger-text: lighten($red, 40%); +$state-danger-bg: $red; +$state-danger-border: darken($state-danger-bg, 20%); + + +//== Popovers +$popover-bg: lighten($gray, 5%); +$popover-border-color: $gray-darker; + +//== Modals +$modal-content-bg: $gray; +$modal-header-border-color: $gray-light; + +//== List group +$list-group-bg: $gray; +$list-group-link-color: $text-color; + +//== Panels +$panel-bg: $gray; +$panel-default-text: $text-color; +$panel-default-border: $gray-darker; +$panel-default-heading-bg: $gray-dark; + +//== Thumbnails +$thumbnail-border: $gray-darker; + +//== Wells +$well-bg: $gray-dark; + +//== Close +$close-color: $gray-lighter; + +//== Type +$hr-border: $gray-light; + +// Variables +$text-color-pale: $gray-light; +$text-color-active: lighten($gray-lighter, 27%); + +$background-grey: $gray-dark; +$background-blue: desaturate(darken($blue, 25%), 15%); + +$border-grey: $gray-darker; +$border-medium-grey: $gray-light; +$border-dark-grey: darken($border-grey, 4.5%); + +$icon-color: $text-color; + +$main-background: $gray-dark; +$framed-background: $gray; +$left-navbar-drawer-background: $main-background; +$hovercard-background: $gray; + +@import 'color_themes/color_theme_override_dark'; diff --git a/app/assets/stylesheets/color_themes/dark/desktop.scss b/app/assets/stylesheets/color_themes/dark/desktop.scss new file mode 100644 index 000000000..92ef0cbea --- /dev/null +++ b/app/assets/stylesheets/color_themes/dark/desktop.scss @@ -0,0 +1,3 @@ +@import 'mixins'; +@import 'color_themes/dark/style'; +@import 'application'; diff --git a/app/assets/stylesheets/color_themes/dark/mobile.scss b/app/assets/stylesheets/color_themes/dark/mobile.scss new file mode 100644 index 000000000..39846a50b --- /dev/null +++ b/app/assets/stylesheets/color_themes/dark/mobile.scss @@ -0,0 +1,63 @@ +@import 'mixins'; +@import 'color_themes/dark/style'; + +// Only overriding existing selectors here, so disable some lint rules +// scss-lint:disable SelectorFormat, NestingDepth, SelectorDepth +body { + .settings-container, + .stream-element, + .login-form { + border: 1px solid $border-grey; + } + + .stream-element, + .comments { + .from a { color: $text-color; } + .info { color: lighten($gray-light, 12%); } + .nsfw-shield { background-color: $gray-light; } + + .bottom-bar { + background: lighten($framed-background, 4.5%); + .post-action .disabled { color: $text-color-pale; } + .post-stats .count { background-color: lighten($framed-background, 4.5%); } + } + + .reshare { + border-bottom: 1px solid $border-medium-grey; + .reshare_via span { color: $border-medium-grey; } + } + } + + .more-link, + .no-more-posts { + background: { color: $btn-default-bg; } + border: 1px solid $gray; + + h1, + h2 { + color: $text-color; + text-shadow: 0 2px 0 $gray; + } + } + + .stream-element.unread { background-color: $gray; } + .stream-element.read { background-color: $gray-darker; } + + .header-full-width { border-bottom: 1px solid $border-grey; } + + .user_aspects { + &, + &:focus, + &:active { + border-color: $gray-light; + } + + &.has_connection { + background-color: $green; + color: $white; + } + } +} +// scss-lint:enable IdSelector, SelectorFormat, NestingDepth, SelectorDepth + +@import 'mobile/mobile'; diff --git a/app/assets/stylesheets/color_themes/original_white/_style.scss b/app/assets/stylesheets/color_themes/original_white/_style.scss index 57228dfdf..448ce77f4 100644 --- a/app/assets/stylesheets/color_themes/original_white/_style.scss +++ b/app/assets/stylesheets/color_themes/original_white/_style.scss @@ -3,7 +3,6 @@ $background: #fff; // Variables $main-background: $background; -$sidebars-background: $background; $card-shadow: none; @import 'color_themes/color_theme_override_origwhite'; diff --git a/app/assets/stylesheets/comments.scss b/app/assets/stylesheets/comments.scss index 3a9828c8f..7b6d76757 100644 --- a/app/assets/stylesheets/comments.scss +++ b/app/assets/stylesheets/comments.scss @@ -1,13 +1,27 @@ .comment_stream { .show_comments { - margin-top: 5px; border-top: 1px solid $border-grey; + line-height: $line-height-computed; + margin-top: 5px; a { color: $text-grey; font-size: 13px; } .media { margin-top: 10px; } } + + .loading-comments { + height: $line-height-computed + 11px; // height of .show_comments: line-height, 10px margin, 1px border + margin-top: -$line-height-computed - 11px; + + .loader { + height: 20px; + width: 20px; + } + + .media { margin: 5px; } + } + .comments > .comment, .comment.new-comment-form-wrapper { .avatar { diff --git a/app/assets/stylesheets/contacts.scss b/app/assets/stylesheets/contacts.scss index a11cc8a93..4d49d39ad 100644 --- a/app/assets/stylesheets/contacts.scss +++ b/app/assets/stylesheets/contacts.scss @@ -38,13 +38,13 @@ margin-right: 25px; } #chat_privilege_toggle > .enabled { - color: #000; + color: $text-color-active; } .contacts-header-icon { font-size: 24.5px; line-height: 40px; - color: lighten($black,75%); - &:hover { color: $black; } + color: $text-color-pale; + &:hover { color: $text-color; } } #suggest_member.btn { margin-top: 8px; } } @@ -56,14 +56,14 @@ font-size: 20px; line-height: 50px; margin: 0 10px; - color: lighten($black,75%); - &:hover { color: $black; } + color: $text-color-pale; + &:hover { color: $text-color; } } &.in_aspect { border-left: 3px solid $brand-success; background-color: lighten($brand-success,35%); } - &:not(.in_aspect) { border-left: 3px solid $white; } + &:not(.in_aspect) { border-left: 3px solid $framed-background; } } .no_contacts { diff --git a/app/assets/stylesheets/conversations.scss b/app/assets/stylesheets/conversations.scss index efb89b669..8c1216cd5 100644 --- a/app/assets/stylesheets/conversations.scss +++ b/app/assets/stylesheets/conversations.scss @@ -17,7 +17,7 @@ } .stream-element { - background-color: $white; + background-color: $framed-background; padding: 10px; .avatar { @@ -30,7 +30,7 @@ .stream-element.message, .stream-element.new-message { - border: 1px solid $light-grey; + border: 1px solid $border-grey; box-shadow: $card-shadow; margin-bottom: 20px; @@ -83,7 +83,7 @@ } } - &.unread { background-color: darken($background-white, 5%); } + &.unread { background-color: $background-grey; } &.selected { background-color: $blue; } .last_author, .last_message { @@ -183,10 +183,60 @@ } // scss-lint:enable SelectorDepth -#new_conversation_pane { +.new-conversation { ul.as-selections { width: 100% !important; } + input#contact_ids { box-shadow: none; } + label { font-weight: bold; } + + .twitter-typeahead, + .tt-menu { + width: 100%; + } +} + +.recipients-tag-list { + .conversation-recipient-tag { + background-color: $brand-primary; + border-radius: $btn-border-radius-base; + display: inline-flex; + margin: 0 2px $form-group-margin-bottom; + padding: 8px; + + &:first-child { margin-left: 0; } + + &:last-child { margin-right: 0; } + + div { + align-self: center; + justify-content: flex-start; + } + } + + .avatar { + height: 40px; + margin-right: 8px; + width: 40px; + } + + .name-and-handle { + color: $white; + margin-right: 8px; + text-align: left; + + .diaspora-id { font-size: $font-size-small; } + } + + .entypo-circled-cross { + color: $white; + cursor: pointer; + font-size: 20px; + height: 22px; + line-height: 22px; + + &:hover { color: $light-grey; } + } } .new-conversation.form-horizontal .form-group:last-of-type { margin-bottom: 0; } diff --git a/app/assets/stylesheets/forms.scss b/app/assets/stylesheets/forms.scss index 98a02a623..2f0717bba 100644 --- a/app/assets/stylesheets/forms.scss +++ b/app/assets/stylesheets/forms.scss @@ -13,9 +13,7 @@ textarea { &:active:focus, &:invalid:focus, &:invalid:required:focus { - border-color: $border-grey; box-shadow: none; - color: $text-dark-grey; } } // scss-lint:enable QualifyingElement @@ -29,7 +27,6 @@ textarea { margin: 20px auto; fieldset { - background-color: $white; margin-bottom: 1em; position: relative; // To correctly place the entypo icon diff --git a/app/assets/stylesheets/header.scss b/app/assets/stylesheets/header.scss index 4d7aa516b..668cef21c 100644 --- a/app/assets/stylesheets/header.scss +++ b/app/assets/stylesheets/header.scss @@ -106,7 +106,7 @@ } .view_all { background-color: $link-color; - border-top: 3px solid $white; + border-top: 3px solid $dropdown-bg; text-align: center; a { color: $white; diff --git a/app/assets/stylesheets/help.scss b/app/assets/stylesheets/help.scss index d5a864770..c19e09439 100644 --- a/app/assets/stylesheets/help.scss +++ b/app/assets/stylesheets/help.scss @@ -98,9 +98,9 @@ ul#help_nav { line-height: 70px; [class^="entypo-"], [class*="entypo-"] { - color: #bfbfbf; + color: $text-color-pale; - &.entypo-chat{ color: #000000; } + &.entypo-chat { color: $text-color-active; } } } } diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss index b661e4b4f..1dd6555ad 100644 --- a/app/assets/stylesheets/home.scss +++ b/app/assets/stylesheets/home.scss @@ -33,8 +33,8 @@ } .landing-info-card { - background-color: $white; - border: 1px solid $light-grey; + background-color: $framed-background; + border: 1px solid $border-grey; box-shadow: $card-shadow; margin-bottom: 25px; margin-top: 25px; diff --git a/app/assets/stylesheets/hovercard.scss b/app/assets/stylesheets/hovercard.scss index 1cf9ae620..ffe8e3cb8 100644 --- a/app/assets/stylesheets/hovercard.scss +++ b/app/assets/stylesheets/hovercard.scss @@ -7,7 +7,7 @@ min-width: 250px; max-width: 400px; - background-color: $background-white; + background-color: $hovercard-background; border: 1px solid $border-dark-grey; font-size: small; diff --git a/app/assets/stylesheets/icons.scss b/app/assets/stylesheets/icons.scss index b4496bbd3..a6cc1f917 100644 --- a/app/assets/stylesheets/icons.scss +++ b/app/assets/stylesheets/icons.scss @@ -1,6 +1,6 @@ [class^="entypo-"], [class*="entypo-"] { font-style: normal; - color: black; + color: $icon-color; &.red { color: #A40802; } &.white { color: white; } diff --git a/app/assets/stylesheets/interactions.scss b/app/assets/stylesheets/interactions.scss index e2f95d677..211f27acd 100644 --- a/app/assets/stylesheets/interactions.scss +++ b/app/assets/stylesheets/interactions.scss @@ -4,7 +4,7 @@ [class^="entypo-"], [class*="entypo-"] { - color: $text-grey; + color: $text-color-pale; font-size: $font-size-base; line-height: $line-height-base; vertical-align: middle; @@ -12,12 +12,12 @@ [class^="entypo-"]:hover, [class*="entypo-"]:hover { - color: $text; + color: $text-color; } &.hide_conversation i { font-size: $line-height-computed * 1.5; } &.delete_conversation i { font-size: $font-size-base * 1.5; } - &.destroy_participation i { color: $black; } + &.destroy_participation i { color: $text-color-active; } &.destroy_participation i:hover { color: $text-dark-grey; } } } diff --git a/app/assets/stylesheets/invitations.scss b/app/assets/stylesheets/invitations.scss index a78bed09f..f7f7451d2 100644 --- a/app/assets/stylesheets/invitations.scss +++ b/app/assets/stylesheets/invitations.scss @@ -1,5 +1,5 @@ #invite_code { - background-color: $white; + background-color: $framed-background; cursor: text; display: block; margin-top: 5px; @@ -7,13 +7,13 @@ #invitationsModal { .modal-header, .modal-body { - color: $text; + color: $text-color; font-size: $font-size-base; text-align: initial; } #paste_link { font-weight: 700; } #invite_code { margin-top: 10px; } - #codes_left { color: $text-grey; } + #codes_left { color: $text-color-pale; } .controls { margin-left: 140px; } #email_invitation { padding-top: 10px; @@ -21,7 +21,7 @@ border-top: 1px dashed $border-grey; label { font-weight: 700; } #already_sent { - color: $text-grey; + color: $text-color-pale; font-size: 12px; } } diff --git a/app/assets/stylesheets/markdown-editor.scss b/app/assets/stylesheets/markdown-editor.scss index cb731118b..e6a679258 100644 --- a/app/assets/stylesheets/markdown-editor.scss +++ b/app/assets/stylesheets/markdown-editor.scss @@ -1,6 +1,6 @@ .md-footer, .md-header { - background: $sidebars-background; + background: $white; border: 0; display: block; height: 42px; @@ -10,7 +10,7 @@ [class^="entypo-"], [class*="entypo-"], .glyphicon { - color: $black; + color: $icon-color; } } @@ -72,7 +72,7 @@ width: 18px; } - &:hover .entypo-cross { color: $text; } + &:hover .entypo-cross { color: $text-color; } } diff --git a/app/assets/stylesheets/mentions.scss b/app/assets/stylesheets/mentions.scss index 71028e629..a6920e7b3 100644 --- a/app/assets/stylesheets/mentions.scss +++ b/app/assets/stylesheets/mentions.scss @@ -75,7 +75,7 @@ } .mentions { - color: white; + color: transparent; font-size: $font-size-base; font-family: Arial, Helvetica, sans-serif; overflow: hidden; diff --git a/app/assets/stylesheets/mobile/comments.scss b/app/assets/stylesheets/mobile/comments.scss index 7f5382c37..e77bf196a 100644 --- a/app/assets/stylesheets/mobile/comments.scss +++ b/app/assets/stylesheets/mobile/comments.scss @@ -33,7 +33,7 @@ &.active:not(.bottom_collapse), &.active:not(.bottom_collapse) > [class^="entypo"] { - color: $text; + color: $text-color; } } diff --git a/app/assets/stylesheets/mobile/conversations.scss b/app/assets/stylesheets/mobile/conversations.scss index e0e02411a..ef3409f79 100644 --- a/app/assets/stylesheets/mobile/conversations.scss +++ b/app/assets/stylesheets/mobile/conversations.scss @@ -61,3 +61,5 @@ .subject { padding: 0 10px; } .message-count, .unread-message-count { margin: 10px 2px; } + +.new-conversation .as-selections { background-color: transparent; } diff --git a/app/assets/stylesheets/mobile/mobile.scss b/app/assets/stylesheets/mobile/mobile.scss index 7996bcee9..1b16f4d09 100644 --- a/app/assets/stylesheets/mobile/mobile.scss +++ b/app/assets/stylesheets/mobile/mobile.scss @@ -150,7 +150,7 @@ footer { border-radius: 5px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); - background-color: #fff; + background-color: $framed-background; margin-bottom: 10px; border: 1px solid #bbb; @@ -176,7 +176,7 @@ footer { border-radius: 3px 3px 0 0; border: { - bottom: 1px solid #ccc; + bottom: 1px solid $border-medium-grey; } img.big-stream-photo { @@ -322,7 +322,7 @@ footer { } .header-full-width { - background-color: #fff; + background-color: $framed-background; border-bottom: 1px solid #aaa; margin: -10px; // Counter the #main padding margin-bottom: 10px; @@ -462,7 +462,7 @@ select { font-weight: bold; color: $text-grey; background: { - color: #fff; + color: $framed-background; } } } diff --git a/app/assets/stylesheets/mobile/tags.scss b/app/assets/stylesheets/mobile/tags.scss index ba5f0ac67..665e41d98 100644 --- a/app/assets/stylesheets/mobile/tags.scss +++ b/app/assets/stylesheets/mobile/tags.scss @@ -3,7 +3,7 @@ ul.followed_tags { margin: 0px; > li { - background-color: $white; + background-color: $framed-background; border: 1px solid $border-grey; border-radius: 5px; box-shadow: 0 1px 2px rgba($border-dark-grey, 0.5); diff --git a/app/assets/stylesheets/notifications.scss b/app/assets/stylesheets/notifications.scss index 16f12513c..27df15086 100644 --- a/app/assets/stylesheets/notifications.scss +++ b/app/assets/stylesheets/notifications.scss @@ -73,7 +73,7 @@ background-color: $background-grey; .unread-toggle { opacity: 1 !important; - .entypo-eye { color: $black; } + .entypo-eye { color: $text-color-active; } } } @@ -90,7 +90,7 @@ padding: 9px 5px; .entypo-eye { cursor: pointer; - color: lighten($black,75%); + color: $text-color-pale; font-size: 17px; line-height: 17px; } diff --git a/app/assets/stylesheets/profile.scss b/app/assets/stylesheets/profile.scss index 727c99fee..cec99ef33 100644 --- a/app/assets/stylesheets/profile.scss +++ b/app/assets/stylesheets/profile.scss @@ -1,7 +1,7 @@ #profile_container { .profile_header { margin-bottom: 15px; - background-color: $white; + background-color: $framed-background; padding-left: 10px; padding-right: 10px; padding-top: 20px; @@ -22,7 +22,7 @@ font-weight: 700; } #diaspora_handle { - color: $text-grey; + color: $text-color-pale; font-size: 20px; } #sharing_message { @@ -64,8 +64,8 @@ .profile-header-icon { font-size: 24.5px; line-height: 30px; - color: lighten($black,75%); - &:hover { color: $black; } + color: $text-color-pale; + &:hover { color: $text-color; } } #mention_button { font-weight: 700; } } @@ -80,8 +80,12 @@ &.active { border-bottom: 3px solid $brand-primary; a { - color: $black; - [class^="entypo-"], [class*="entypo-"] { color: $black; } + color: $text-color-active; + + [class^="entypo-"], + [class*="entypo-"] { + color: $text-color-active; + } } } a { @@ -94,9 +98,13 @@ margin-right: 2px; } &:hover { - color: $black; - [class^="entypo-"], [class*="entypo-"] { color: $black; } + color: $text-color-active; text-decoration: none; + + [class^="entypo-"], + [class*="entypo-"] { + color: $text-color-active; + } } } } diff --git a/app/assets/stylesheets/registration.scss b/app/assets/stylesheets/registration.scss index 53c65674d..123161d6a 100644 --- a/app/assets/stylesheets/registration.scss +++ b/app/assets/stylesheets/registration.scss @@ -35,7 +35,7 @@ } .captcha-input { - border-bottom: 1px solid $border-grey; + border-bottom: 1px solid $input-border; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; box-sizing: border-box; diff --git a/app/assets/stylesheets/sidebar.scss b/app/assets/stylesheets/sidebar.scss index 1df833b42..a09f5d84b 100644 --- a/app/assets/stylesheets/sidebar.scss +++ b/app/assets/stylesheets/sidebar.scss @@ -1,7 +1,7 @@ .sidebar, .framed-content { - background-color: $white; - border: 1px solid $light-grey; + background-color: $framed-background; + border: 1px solid $border-grey; border-top: 0; box-shadow: $card-shadow; diff --git a/app/assets/stylesheets/stream_element.scss b/app/assets/stylesheets/stream_element.scss index e9f466676..317c8db7e 100644 --- a/app/assets/stylesheets/stream_element.scss +++ b/app/assets/stylesheets/stream_element.scss @@ -15,7 +15,7 @@ position: relative; .control-icons { - background: $white; + background: $framed-background; border-radius: 4px; padding-left: 4px; position: absolute; @@ -26,7 +26,7 @@ } .thumbnail { - background: $white; + background: $framed-background; border-radius: 0; box-shadow: $card-shadow; height: 240px; @@ -40,7 +40,7 @@ &:hover, &:focus, &:active { - border-color: $light-grey; + border-color: $border-grey; text-decoration: none; } @@ -62,7 +62,7 @@ #main_stream .stream-element { margin-bottom: 20px; - border: 1px solid $light-grey; + border: 1px solid $border-grey; box-shadow: $card-shadow; &.highlighted { @@ -72,7 +72,7 @@ } .stream-element { - background-color: $white; + background-color: $framed-background; padding: 10px; & > .media { diff --git a/app/assets/templates/comment-stream_tpl.jst.hbs b/app/assets/templates/comment-stream_tpl.jst.hbs index 0b6678a10..e7343507d 100644 --- a/app/assets/templates/comment-stream_tpl.jst.hbs +++ b/app/assets/templates/comment-stream_tpl.jst.hbs @@ -6,6 +6,14 @@ + +
{{#if loggedIn}} diff --git a/app/assets/templates/conversation_recipient_tag_tpl.jst.hbs b/app/assets/templates/conversation_recipient_tag_tpl.jst.hbs new file mode 100644 index 000000000..296c0b7f9 --- /dev/null +++ b/app/assets/templates/conversation_recipient_tag_tpl.jst.hbs @@ -0,0 +1,12 @@ +
+
+ +
+
+
{{ name }}
+
{{ handle }}
+
+
+ +
+
diff --git a/app/assets/templates/header_tpl.jst.hbs b/app/assets/templates/header_tpl.jst.hbs index a895d99c9..ab8a27a95 100644 --- a/app/assets/templates/header_tpl.jst.hbs +++ b/app/assets/templates/header_tpl.jst.hbs @@ -53,7 +53,7 @@