diff --git a/app/assets/javascripts/community_order.js b/app/assets/javascripts/community_order.js new file mode 100644 index 000000000..e7c00df8b --- /dev/null +++ b/app/assets/javascripts/community_order.js @@ -0,0 +1,34 @@ +document.addEventListener('DOMContentLoaded', () => { + const pref = /** @type {HTMLElement} */(document.querySelector(".community-sortable")); + const el = /** @type {HTMLElement} */(pref.querySelector(".sortable")); + const input = /** @type {HTMLInputElement} */(pref.querySelector(".js-user-pref")); + + const sortable = Sortable.create(el, { + store: { + get: () => input.value.split(','), + set: self => { + input.value = self.toArray().join(','); + input.dispatchEvent(new Event("change")); + } + } + }); + + document.querySelectorAll('.community-sortable-list-item').forEach(el => { + el.querySelector('.sort-top-btn')?.addEventListener('click', _ => { + el.parentElement.insertAdjacentElement('afterbegin', el); + sortable.save(); + }); + el.querySelector('.sort-up-btn')?.addEventListener('click', _ => { + el.previousElementSibling?.insertAdjacentElement('beforebegin', el); + sortable.save(); + }); + el.querySelector('.sort-down-btn')?.addEventListener('click', _ => { + el.nextElementSibling?.insertAdjacentElement('afterend', el); + sortable.save(); + }); + el.querySelector('.sort-bottom-btn')?.addEventListener('click', _ => { + el.parentElement.insertAdjacentElement('beforeend', el); + sortable.save(); + }); + }) +}); \ No newline at end of file diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss index 3835a2878..05118f9fe 100644 --- a/app/assets/stylesheets/users.scss +++ b/app/assets/stylesheets/users.scss @@ -187,6 +187,38 @@ img { } } +.user-pref.user-block-pref { + flex-direction: column; + align-items: flex-start; +} + +.community-sortable { + .community-sortable-list-item { + display: flex; + justify-content: flex-start; + align-items: center; + cursor: grab; + img { + max-height: 1.5rem; + } + .img { + width: 100px; + padding: 10px; + } + .label { + flex-grow: 1; + } + .sortable-buttons { + display: flex; + flex-direction: column; + } + .community-label { + display: flex; + align-items: center; + } + } +} + $sizes: (16, 32, 40, 48, 64, 128, 256); @each $size in $sizes { diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 62372c684..cb94a1de0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -32,7 +32,7 @@ def upload end def dashboard - @communities = Community.all + @communities = Community.all.user_preferred_order(current_user) @edits = Post.unscoped do SuggestedEdit.unscoped.joins(:post).where(active: true).group(Arel.sql('posts.category_id')).count end diff --git a/app/models/community.rb b/app/models/community.rb index d6eca7ac3..901bf3eb1 100644 --- a/app/models/community.rb +++ b/app/models/community.rb @@ -5,4 +5,23 @@ class Community < ApplicationRecord default_scope { where(is_fake: false) } validates :host, uniqueness: { case_sensitive: false } + + scope :user_preferred_order, lambda { |user| + if user.nil? + all + else + user_order = user.preference('community_order', community: false) + .split(',') + .map(&:to_i) + + # For some reason, even though we pass in filter: false, + # if user_order is empty, in_order_of still returns an empty array. + # Therefore we have to special case this + if user_order.empty? + all + else + in_order_of(:id, user_order, filter: false) + end + end + } end diff --git a/app/views/application/dashboard.html.erb b/app/views/application/dashboard.html.erb index 2843a3336..cdea593ce 100644 --- a/app/views/application/dashboard.html.erb +++ b/app/views/application/dashboard.html.erb @@ -8,6 +8,10 @@
All communities, with their categories. You can also see the communities from the dropdown arrow at the top right of each page. + <% if user_signed_in? %> + You may change the order in which these communities appear in + <%= link_to 'your preferences', user_preferences_path %>. + <% end %>