diff --git a/apps/profile/models.py b/apps/profile/models.py index 44379a43b..e2219351c 100644 --- a/apps/profile/models.py +++ b/apps/profile/models.py @@ -2135,24 +2135,37 @@ class MDashboardRiver(mongo.Document): def get_user_rivers(cls, user_id): return cls.objects(user_id=user_id) + @classmethod + def remove_river(cls, user_id, river_side, river_order): + try: + river = cls.objects.get(user_id=user_id, river_side=river_side, river_order=river_order) + except cls.DoesNotExist: + return + + river.delete() + + for r, river in enumerate(cls.objects.filter(user_id=user_id, river_side=river_side)): + if river.river_order != r: + logging.debug(f" ---> Rebalancing {river} from {river.river_order} to {r}") + river.river_order = r + river.save() + @classmethod def save_user(cls, user_id, river_id, river_side, river_order): try: river = cls.objects.get(user_id=user_id, river_side=river_side, river_order=river_order) except cls.DoesNotExist: river = None - + if not river: river = cls.objects.create(user_id=user_id, river_id=river_id, - river_side=river_side, river_order=river_order) + river_side=river_side, river_order=river_order) river.river_id = river_id river.river_side = river_side river.river_order = river_order river.save() - return river - class RNewUserQueue: KEY = "new_user_queue" diff --git a/apps/reader/urls.py b/apps/reader/urls.py index 8d601b3e7..9f829e59e 100644 --- a/apps/reader/urls.py +++ b/apps/reader/urls.py @@ -64,4 +64,5 @@ urlpatterns = [ url(r'^save_search', views.save_search, name='save-search'), url(r'^delete_search', views.delete_search, name='delete-search'), url(r'^save_dashboard_river', views.save_dashboard_river, name='save-dashboard-river'), + url(r'^remove_dashboard_river', views.remove_dashboard_river, name='remove-dashboard-river'), ] diff --git a/apps/reader/views.py b/apps/reader/views.py index 0ad309997..48f8a25f9 100644 --- a/apps/reader/views.py +++ b/apps/reader/views.py @@ -2877,7 +2877,7 @@ def delete_search(request): def save_dashboard_river(request): river_id = request.POST['river_id'] river_side = request.POST['river_side'] - river_order = request.POST['river_order'] + river_order = int(request.POST['river_order']) logging.user(request, "~FCSaving dashboard river: ~SB%s~SN (%s %s)" % (river_id, river_side, river_order)) @@ -2887,3 +2887,19 @@ def save_dashboard_river(request): return { 'dashboard_rivers': dashboard_rivers, } + +@required_params('river_id', 'river_side', 'river_order') +@json.json_view +def remove_dashboard_river(request): + river_id = request.POST['river_id'] + river_side = request.POST['river_side'] + river_order = int(request.POST['river_order']) + + logging.user(request, "~FRRemoving~FC dashboard river: ~SB%s~SN (%s %s)" % (river_id, river_side, river_order)) + + MDashboardRiver.remove_river(request.user.pk, river_side, river_order) + dashboard_rivers = MDashboardRiver.get_user_rivers(request.user.pk) + + return { + 'dashboard_rivers': dashboard_rivers, + } diff --git a/media/css/reader/reader.css b/media/css/reader/reader.css index eb064e732..6f386d4ac 100644 --- a/media/css/reader/reader.css +++ b/media/css/reader/reader.css @@ -4436,6 +4436,10 @@ body { text-align: center; width: 132px; line-height: 12px; + transition: width 0.12s ease-out; +} +.NB-story-starred .NB-feed-story-sideoptions-container { + width: 194px; } .NB-narrow-content .NB-feed-story-sideoptions-container { @@ -4576,7 +4580,7 @@ body { margin: 0; } .NB-sideoption-save { - padding: 4px 12px 6px; + padding: 4px 6px 6px; border: 1px solid #DBE6EA; text-align: left; color: #606060; @@ -4586,14 +4590,13 @@ body { margin: 11px 2px 0 0; width: 16px; height: 16px; - background: transparent url("/media/img/icons/nouncs/tag.svg") no-repeat 0 0; + background: transparent url("/media/img/icons/nouns/tag.svg") no-repeat 0 0; background-size: 14px; } .NB-sideoption-save .NB-sideoption-save-title { text-transform: uppercase; font-size: 10px; text-align: left; - text-shadow: 0 1px 0 #F6F6F6; color: #202020; margin: 12px 0 4px; } @@ -4618,6 +4621,7 @@ body { color: white; font-weight: bold; cursor: pointer; + display: inline-block; } .NB-sideoption-save .NB-sideoption-save-populate:hover { background-color: rgba(205, 205, 205, .8); @@ -5949,7 +5953,8 @@ form.opml_import_form input { .NB-dashboard-columns-triple .NB-splash-modules .NB-account-wide { margin: 0 24px; } -.NB-dashboard-columns-triple .NB-dashboard-rivers-left { +.NB-dashboard-columns-triple .NB-dashboard-rivers-left, +.NB-dashboard-columns-triple .NB-dashboard-rivers-right { display: flex; flex-wrap: nowrap; flex-direction: row; @@ -5957,16 +5962,20 @@ form.opml_import_form input { justify-content: center; gap: 24px; } -.NB-density-compact.NB-dashboard-columns-triple .NB-dashboard-rivers-left { +.NB-density-compact.NB-dashboard-columns-triple .NB-dashboard-rivers-left, +.NB-density-compact.NB-dashboard-columns-triple .NB-dashboard-rivers-right { gap: 4px; } -.NB-dashboard-columns-triple .NB-dashboard-rivers-left .NB-dashboard-river { +.NB-dashboard-columns-triple .NB-dashboard-rivers-left .NB-dashboard-river, +.NB-dashboard-columns-triple .NB-dashboard-rivers-right .NB-dashboard-river { flex-basis: 100%; } -.NB-dashboard-columns-triple .NB-dashboard-rivers-left > * { +.NB-dashboard-columns-triple .NB-dashboard-rivers-left > *, +.NB-dashboard-columns-triple .NB-dashboard-rivers-right > * { flex: 1; } -.NB-dashboard-columns-triple .NB-dashboard-rivers-left .NB-feedbar-options { +.NB-dashboard-columns-triple .NB-dashboard-rivers-left .NB-feedbar-options, +.NB-dashboard-columns-triple .NB-dashboard-rivers-right .NB-feedbar-options { text-indent: 258%; white-space: nowrap; overflow: hidden; @@ -7635,7 +7644,8 @@ form.opml_import_form input { .NB-module-header { transition: margin 0.24s ease-out; } -.NB-modules-center .NB-module { +.NB-dashboard-rivers-left .NB-module, +.NB-dashboard-rivers-right .NB-module { margin: 0 0 34px; clear: both; } @@ -7648,7 +7658,7 @@ form.opml_import_form input { .NB-module-river .NB-module-river-favicon { display: inline-block; cursor: pointer; -/* flex: 1; */} +} .NB-module-river .NB-module-river-favicon img { width: 16px; height: 16px; @@ -7659,12 +7669,15 @@ form.opml_import_form input { display: inline-block; cursor: pointer; text-align: left; -display: flex;justify-content: center;} + display: flex; + justify-content: center; +} .NB-module-river .NB-dashboard-column-control { float: left; line-height: 0; display: none; -margin-right: 6px;} + margin-right: 6px; +} .NB-module-river .NB-dashboard-column-control.NB-active { display: inline-block; } @@ -13444,6 +13457,48 @@ margin-right: 6px;} } .NB-filter-popover .NB-modal-feed-chooser { width: 100%; + margin: 0 0 6px; +} +.NB-filter-popover .NB-filter-popover-manage-dashboard-modules { + display: flex; + gap: 6px; +} +.NB-filter-popover .NB-filter-popover-manage-button { + flex: 1 2 0; + border-radius: 4px; + font-size: 12px; + margin: 2px 0; + padding: 4px 6px; + display: flex; + gap: 6px; +} +.NB-filter-popover .NB-filter-popover-manage-button:hover { + cursor: pointer; + background-color: #d5d6d2; +} +.NB-filter-popover .NB-filter-popover-manage-button .NB-icon { + /* flex: 1 1 0; */ + width: 16px; + height: 16px; +} +.NB-filter-popover .NB-filter-popover-manage-button .NB-text { + flex: 2 1 0; +} +.NB-filter-popover .NB-filter-popover-dashboard-add-module-left .NB-icon { + background: transparent url('/media/embed/icons/nouns/add-list.svg') no-repeat 0 0; + background-size: 16px; +} +.NB-filter-popover .NB-filter-popover-dashboard-add-module-right .NB-icon { + background: transparent url('/media/embed/icons/nouns/add-list-right.svg') no-repeat 0 0; + background-size: 16px; + order: 2; +} +.NB-filter-popover .NB-filter-popover-dashboard-remove-module .NB-icon { + background: transparent url('/media/embed/icons/nouns/remove-list.svg') no-repeat 0 0; + background-size: 16px; +} +.NB-filter-popover .NB-filter-popover-dashboard-add-module-right .NB-text { + text-align: right; } .NB-feedbar-options-stat { position: relative; diff --git a/media/img/icons/nouns/add-list-right.svg b/media/img/icons/nouns/add-list-right.svg new file mode 100644 index 000000000..ae880f3c3 --- /dev/null +++ b/media/img/icons/nouns/add-list-right.svg @@ -0,0 +1,13 @@ + + + add-list-right + + + + + + + + + + \ No newline at end of file diff --git a/media/img/icons/nouns/add-list.svg b/media/img/icons/nouns/add-list.svg new file mode 100644 index 000000000..4fd06d0ee --- /dev/null +++ b/media/img/icons/nouns/add-list.svg @@ -0,0 +1,13 @@ + + + add-list + + + + + + + + + + \ No newline at end of file diff --git a/media/img/icons/nouns/remove-list.svg b/media/img/icons/nouns/remove-list.svg new file mode 100644 index 000000000..27dabed7c --- /dev/null +++ b/media/img/icons/nouns/remove-list.svg @@ -0,0 +1,13 @@ + + + remove-list + + + + + + + + + + \ No newline at end of file diff --git a/media/img/originals/Nouns.sketch b/media/img/originals/Nouns.sketch index aff5a04cd..b641689ed 100644 Binary files a/media/img/originals/Nouns.sketch and b/media/img/originals/Nouns.sketch differ diff --git a/media/js/newsblur/common/assetmodel.js b/media/js/newsblur/common/assetmodel.js index 1746c9095..da902343e 100644 --- a/media/js/newsblur/common/assetmodel.js +++ b/media/js/newsblur/common/assetmodel.js @@ -1850,6 +1850,17 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({ }, this), error_callback); }, + remove_dashboard_river: function (river_id, river_side, river_order, callback, error_callback) { + this.make_request('/reader/remove_dashboard_river', { + river_id: river_id, + river_side: river_side, + river_order: river_order + }, _.bind(function (response) { + this.dashboard_rivers.reset(response.dashboard_rivers); + callback && callback(response); + }, this), error_callback); + }, + follow_user: function(user_id, callback) { this.make_request('/social/follow', {'user_id': user_id}, _.bind(function(data) { NEWSBLUR.log(["follow data", data]); diff --git a/media/js/newsblur/reader/reader.js b/media/js/newsblur/reader/reader.js index cfab96a5d..2c8ee123e 100644 --- a/media/js/newsblur/reader/reader.js +++ b/media/js/newsblur/reader/reader.js @@ -4851,13 +4851,13 @@ NEWSBLUR.assets.save_dashboard_river("river:global", "left", 2, _.bind(function () { this.load_dashboard_rivers(); }, this), function (e) { - console.log(['Error saving dashbaord river', e]); + console.log(['Error saving dashboard river', e]); }); }, this), function (e) { - console.log(['Error saving dashbaord river', e]); + console.log(['Error saving dashboard river', e]); }); }, this), function (e) { - console.log(['Error saving dashbaord river', e]); + console.log(['Error saving dashboard river', e]); }); } }, diff --git a/media/js/newsblur/views/dashboard_river_view.js b/media/js/newsblur/views/dashboard_river_view.js index 3f2acbdb9..1bbd50408 100644 --- a/media/js/newsblur/views/dashboard_river_view.js +++ b/media/js/newsblur/views/dashboard_river_view.js @@ -438,6 +438,8 @@ NEWSBLUR.Views.DashboardRiver = Backbone.View.extend({ NEWSBLUR.FeedOptionsPopover.create({ anchor: this.$(".NB-feedbar-options"), feed_id: this.model.get('river_id'), + river_side: this.model.get('river_side'), + river_order: this.model.get('river_order'), on_dashboard: this, show_markscroll: false }); diff --git a/media/js/newsblur/views/feed_options_popover.js b/media/js/newsblur/views/feed_options_popover.js index ed089095d..cd90d8b46 100644 --- a/media/js/newsblur/views/feed_options_popover.js +++ b/media/js/newsblur/views/feed_options_popover.js @@ -25,6 +25,9 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({ "click .NB-filter-popover-filter-icon": "open_site_settings", "click .NB-filter-popover-stats-icon": "open_site_statistics", "click .NB-filter-popover-notifications-icon": "open_notifications", + "click .NB-filter-popover-dashboard-add-module-left": "add_dashboard_module_left", + "click .NB-filter-popover-dashboard-add-module-right": "add_dashboard_module_right", + "click .NB-filter-popover-dashboard-remove-module": "remove_dashboard_module", "change .NB-modal-feed-chooser": "change_feed" }, @@ -35,7 +38,7 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({ if (NEWSBLUR.reader.active_feed == "read") { this.options['show_readfilter'] = false; } - if (NEWSBLUR.reader.active_feed == "river:infrequent") { + if (_.contains([NEWSBLUR.reader.active_feed, this.options.feed_id], "river:infrequent")) { this.options['show_infrequent'] = true; } if (NEWSBLUR.reader.flags['starred_view']) { @@ -81,16 +84,32 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({ include_special_folders: true }) ]), - $.make('ul', { className: 'segmented-control NB-menu-manage-view-setting-dashboardcount' }, [ - $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-5 NB-active', role: "button" }, '5 stories'), - $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-10', role: "button" }, '10'), - $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-15', role: "button" }, '15'), - $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-20', role: "button" }, '20'), + $.make('div', { className: 'NB-filter-popover-manage-dashboard-modules' }, [ + $.make('div', { className: 'NB-filter-popover-manage-button NB-filter-popover-dashboard-add-module-left' }, [ + $.make('div', { className: 'NB-icon' }), + $.make('div', { className: 'NB-text' }, "Add story list") + ]), + $.make('div', { className: 'NB-filter-popover-manage-button NB-filter-popover-dashboard-add-module-right' }, [ + $.make('div', { className: 'NB-icon' }), + $.make('div', { className: 'NB-text' }, "Add story list") + ]) + ]), + $.make('div', { className: 'NB-filter-popover-manage-dashboard-modules' }, [ + $.make('div', { className: 'NB-filter-popover-manage-button NB-filter-popover-dashboard-remove-module' }, [ + $.make('div', { className: 'NB-icon' }), + $.make('div', { className: 'NB-text' }, "Remove this list") + ]), ]) ])), $.make('div', { className: 'NB-popover-section' }, [ (is_feed && $.make('div', { className: 'NB-section-icon NB-filter-popover-filter-icon' })), $.make('div', { className: 'NB-popover-section-title' }, 'Filter stories'), + (this.options.on_dashboard && $.make('ul', { className: 'segmented-control NB-menu-manage-view-setting-dashboardcount' }, [ + $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-5 NB-active', role: "button" }, '5 stories'), + $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-10', role: "button" }, '10'), + $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-15', role: "button" }, '15'), + $.make('li', { className: 'NB-view-setting-option NB-view-setting-dashboardcount-20', role: "button" }, '20'), + ])), (this.options.show_readfilter && $.make('ul', { className: 'segmented-control NB-menu-manage-view-setting-readfilter' }, [ $.make('li', { className: 'NB-view-setting-option NB-view-setting-readfilter-all NB-active', role: "button" }, 'All stories'), $.make('li', { className: 'NB-view-setting-option NB-view-setting-readfilter-unread', role: "button" }, 'Unread only') @@ -344,19 +363,19 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({ NEWSBLUR.reader.apply_story_styling(true); } else if ($target.hasClass("NB-view-setting-infrequent-5")) { NEWSBLUR.assets.preference('infrequent_stories_per_month', 5); - NEWSBLUR.reader.reload_feed(); + this.reload_feed(); } else if ($target.hasClass("NB-view-setting-infrequent-15")) { NEWSBLUR.assets.preference('infrequent_stories_per_month', 15); - NEWSBLUR.reader.reload_feed(); + this.reload_feed(); } else if ($target.hasClass("NB-view-setting-infrequent-30")) { NEWSBLUR.assets.preference('infrequent_stories_per_month', 30); - NEWSBLUR.reader.reload_feed(); + this.reload_feed(); } else if ($target.hasClass("NB-view-setting-infrequent-60")) { NEWSBLUR.assets.preference('infrequent_stories_per_month', 60); - NEWSBLUR.reader.reload_feed(); + this.reload_feed(); } else if ($target.hasClass("NB-view-setting-infrequent-90")) { NEWSBLUR.assets.preference('infrequent_stories_per_month', 90); - NEWSBLUR.reader.reload_feed(); + this.reload_feed(); } else if ($target.hasClass("NB-options-feed-size-xs")) { this.update_feed_font_size('xs'); } else if ($target.hasClass("NB-options-feed-size-s")) { @@ -396,6 +415,10 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({ var changed = NEWSBLUR.assets.view_setting(this.options.feed_id, setting); if (!changed) return; + this.reload_feed(); + }, + + reload_feed: function () { if (this.options.on_dashboard) { this.options.on_dashboard.initialize(); } else { @@ -422,6 +445,41 @@ NEWSBLUR.FeedOptionsPopover = NEWSBLUR.ReaderPopover.extend({ }, this)); }, + add_dashboard_module: function (side) { + var count = NEWSBLUR.assets.dashboard_rivers.side(side).length; + var folder_names = NEWSBLUR.assets.folders.child_folder_names(); + var random_feed = "river:"; + if (folder_names.length) { + random_feed = "river:" + folder_names[_.random(folder_names.length)];; + } + NEWSBLUR.assets.save_dashboard_river(random_feed, side, count, _.bind(function () { + NEWSBLUR.reader.load_dashboard_rivers(true); + this.close(); + }, this), function (e) { + console.log(['Error saving dashboard river', e]); + }); + }, + + add_dashboard_module_left: function () { + this.add_dashboard_module("left"); + }, + + add_dashboard_module_right: function () { + this.add_dashboard_module("right"); + }, + + remove_dashboard_module: function () { + var river_id = this.options.feed_id; + var river_side = this.options.river_side; + var river_order = this.options.river_order; + NEWSBLUR.assets.remove_dashboard_river(river_id, river_side, river_order, _.bind(function () { + NEWSBLUR.reader.load_dashboard_rivers(true); + this.close(); + }, this), function (e) { + console.log(['Error saving dashboard river', e]); + }); + }, + change_feed: function () { var feed_id = this.$(".NB-modal-feed-chooser").val(); console.log(['Changing feed', feed_id]) diff --git a/media/js/newsblur/views/story_save_view.js b/media/js/newsblur/views/story_save_view.js index 45b382323..73a0bf43b 100644 --- a/media/js/newsblur/views/story_save_view.js +++ b/media/js/newsblur/views/story_save_view.js @@ -159,6 +159,7 @@ NEWSBLUR.Views.StorySaveView = Backbone.View.extend({ var sideoption_content_height = $save_clone.height(); $save_clone.remove(); var new_sideoptions_height = $sideoption_container.height() - $save_wrapper.height() + sideoption_content_height; + // console.log(['Save options height', new_sideoptions_height, $sideoption_container.height(), $save_wrapper.height(), sideoption_content_height]) if (!options.close) { $sideoption.addClass('NB-active'); $save_wrapper.addClass('NB-active'); @@ -278,4 +279,4 @@ NEWSBLUR.Views.StorySaveView = Backbone.View.extend({ } -}); \ No newline at end of file +});