Introduce quick filters on the page so the dialog becomes advanced filtering

This commit is contained in:
Jason Zimdars
2025-02-20 15:20:30 -06:00
parent 508fb8e3f7
commit 1ad6a9adb8
10 changed files with 288 additions and 28 deletions
+6
View File
@@ -93,3 +93,9 @@
max-inline-size: calc(100dvw - (2 * var(--block-space-double)));
z-index: 1;
}
.quick-filter:has(input:not(.default-value):checked) {
.input--select {
--input-background: var(--color-selected);
}
}
+6
View File
@@ -10,4 +10,10 @@ module FiltersHelper
name = params[key].is_a?(Array) ? "#{key}[]" : key
hidden_field_tag name, value, id: nil
end
def any_filters?(filter)
filter.tags.any? || filter.assignees.any? || filter.assigners.any? ||
filter.stages.any? || filter.terms.any? ||
filter.assignment_status.unassigned? || !filter.default_indexed_by?
end
end
+51
View File
@@ -0,0 +1,51 @@
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<% if filter.assignment_status.unassigned? %>
No one
<% elsif filter.assignees.any? %>
<%= filter.assignees.map(&:name).to_sentence %>
<% else %>
Assigned to…
<% end %>
</span>
</button>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half overflow-ellipsis">Assigned to…</strong>
<%= form_with url: bubbles_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<% filter.as_params.except(:assignee_ids, :assignment_status).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<%= link_to bubbles_path(filter.as_params.except(:assignee_ids, :assignment_status)), class: "btn popup__item" do %>
<span class="overflow-ellipsis">Clear all</span>
<% end %>
<div class="btn popup__item">
<%= form.check_box "assignment_status", {
checked: filter.assignment_status.unassigned?,
data: { action: "change->form#submit" },
include_hidden: false,
}, "unassigned" %>
<%= form.label :assignment_status, "No one", class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% Current.account.users.active.order(:name).each do |user| %>
<div class="btn popup__item">
<%= form.check_box "assignee_ids[]", {
checked: filter.assignees.include?(user),
data: { action: "change->form#submit" },
include_hidden: false,
}, user.id %>
<%= form.label "assignee_ids[]", user.name, for: dom_id(user, :filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
<% end %>
</dialog>
</div>
+51
View File
@@ -0,0 +1,51 @@
<% if filter.assigners.any? %>
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<% if filter.assigners.any? %>
<%= "By #{filter.assigners.map(&:name).to_sentence}" %>
<% else %>
Assigned by…
<% end %>
</span>
</button>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">Assigned by…</strong>
<%= form_with url: bubbles_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<% filter.as_params.except(:assigner_ids).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<%= link_to bubbles_path(filter.as_params.except(:assigner_ids)), class: "btn popup__item" do %>
<span class="overflow-ellipsis">Clear all</span>
<% end %>
<div class="btn popup__item">
<%= form.check_box "assigner_ids[]", {
checked: filter.assigners.include?(Current.user),
data: { action: "change->form#submit" },
include_hidden: false,
}, Current.user.id %>
<%= form.label "assigner_ids[]", "Me", for: dom_id(Current.user, :assigner_filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% Current.account.users.active.without(Current.user).order(:name).each do |user| %>
<div class="btn popup__item">
<%= form.check_box "assigner_ids[]", {
checked: filter.assigners.include?(user),
data: { action: "change->form#submit" },
include_hidden: false,
}, user.id %>
<%= form.label "assigner_ids[]", user.name, for: dom_id(user, :assigner_filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
<% end %>
</dialog>
</div>
<% end %>
+40
View File
@@ -0,0 +1,40 @@
<% if filter.buckets.many? %>
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<% if filter.buckets.any? %>
<%= filter.buckets.map(&:name).to_sentence %>
<% else %>
In collection
<% end %>
</span>
</button>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">In collection</strong>
<%= form_with url: bubbles_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<% filter.as_params.except(:bucket_ids).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<%= link_to bubbles_path(filter.as_params.except(:bucket_ids)), class: "btn popup__item" do %>
<span class="overflow-ellipsis">Clear all</span>
<% end %>
<% filter.buckets.order(:name).each do |bucket| %>
<div class="btn popup__item">
<%= form.check_box "bucket_ids[]", {
checked: filter.buckets.include?(bucket),
data: { action: "change->form#submit" },
include_hidden: false,
}, bucket.id %>
<%= form.label "bucket_ids[]", bucket.name, for: dom_id(bucket, :filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
<% end %>
</dialog>
</div>
<% end %>
+1 -1
View File
@@ -59,7 +59,7 @@
</menu>
<menu class="filter__menu">
<li class="filter__label"><strong>In Project</strong></li>
<li class="filter__label"><strong>In Collection</strong></li>
<li>
<%= button_tag type: :button, class: "btn filter__button", data: { action: "filter-form#clearCategory", filter_form_name_param: "bucket_ids[]" } do %>
+38
View File
@@ -0,0 +1,38 @@
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<%= filter.indexed_by.humanize %>
</span>
</button>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">Sort by…</strong>
<%= form_with url: bubbles_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<% filter.as_params.except(:indexed_by).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<div class="btn popup__item">
<%= form.radio_button :indexed_by, filter.default_indexed_by,
checked: filter.default_indexed_by?,
class: "default-value",
data: { action: "change->form#submit" } %>
<%= form.label :indexed_by, "Most active", value: filter.default_indexed_by, class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% Filter::INDEXES.each do |index| %>
<div class="btn popup__item">
<%= form.radio_button :indexed_by, index,
checked: filter.indexed_by == index,
data: { action: "change->form#submit" } %>
<%= form.label :indexed_by, index.humanize, value: index, class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
<% end %>
</dialog>
</div>
+13 -27
View File
@@ -5,36 +5,22 @@
</button>
<div class="flex-inline center align-center gap-half">
<%= filter_chip_tag filter.indexed_by.humanize, filter.as_params_without(:indexed_by, filter.indexed_by) unless filter.default_indexed_by? %>
<% filter.tags.each do |tag| %>
<%= filter_chip_tag tag.hashtag, filter.as_params_without(:tag_ids, tag.id) %>
<% end %>
<% filter.assignees.each do |assignee| %>
<%= filter_chip_tag "for #{assignee.name}", filter.as_params_without(:assignee_ids, assignee.id) %>
<% end %>
<% if filter.assignment_status.present? %>
<%= filter_chip_tag filter.assignment_status.humanize, filter.as_params_without(:assignment_status, filter.assignment_status) %>
<% end %>
<% filter.assigners.each do |assigner| %>
<%= filter_chip_tag "by #{assigner.name}", filter.as_params_without(:assigner_ids, assigner.id) %>
<% end %>
<% filter.stages.each do |stage| %>
<%= filter_chip_tag "in #{stage.name}", filter.as_params_without(:stage_ids, stage.id) %>
<% end %>
<% if filter.buckets.many? %>
<% filter.buckets.each do |bucket| %>
<%= filter_chip_tag "in #{bucket.name}", filter.as_params_without(:bucket_ids, bucket.id) %>
<% end %>
<% end %>
<%= render "filters/indexed_by", filter: filter %>
<%= render "filters/buckets", filter: filter %>
<%= render "filters/tags", filter: filter %>
<%= render "filters/assignees", filter: filter %>
<%= render "filters/assigners", filter: filter %>
<%= render "filters/stages", filter: filter %>
<% filter.terms.each do |term| %>
<%= filter_chip_tag %Q("#{term}"), filter.as_params_without(:terms, term) %>
<% end %>
<% if any_filters?(filter) %>
<%= link_to bubbles_path, class: "btn btn--remove txt-small" do %>
<%= image_tag "close.svg", aria: { hidden: true }, size: 24 %>
<span class="for-screen-reader">Clear all</span>
<% end %>
<% end %>
</div>
</div>
+44
View File
@@ -0,0 +1,44 @@
<% if Current.account.workflows.any? && filter.stages.any? %>
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<% if filter.stages.any? %>
<%= filter.stages.map(&:name).to_sentence %>
<% else %>
In stage…
<% end %>
</span>
</button>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half">In stage…</strong>
<%= form_with url: bubbles_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<% filter.as_params.except(:stage_ids).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<%= link_to bubbles_path(filter.as_params.except(:stage_ids)), class: "btn popup__item" do %>
<span class="overflow-ellipsis">Clear all</span>
<% end %>
<% Current.account.workflows.order(:name).each do |workflow| %>
<strong class="popup__title margin-block-start-half pad-inline-half flex overflow-ellipsis"><%= workflow.name %></strong>
<% workflow.stages.order(:name).each do |stage| %>
<div class="btn popup__item">
<%= form.check_box "stage_ids[]", {
checked: filter.stages.include?(stage),
data: { action: "change->form#submit" },
include_hidden: false,
}, stage.id %>
<%= form.label "stage_ids[]", stage.name, for: dom_id(stage, :filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
<% end %>
<% end %>
</dialog>
</div>
<% end %>
+38
View File
@@ -0,0 +1,38 @@
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
<span class="overflow-ellipsis">
<% if filter.tags.any? %>
<%= filter.tags.map(&:hashtag).to_sentence %>
<% else %>
Tagged…
<% end %>
</span>
</button>
<dialog class="events__popup popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
<strong class="popup__title margin-block-start-half pad-inline-half overflow-ellipsis">Tagged…</strong>
<%= form_with url: bubbles_path, method: :get, class: "flex flex-column full-width popup__list",
data: { controller: "form" } do |form| %>
<% filter.as_params.except(:tag_ids).each do |key, value| %>
<%= filter_hidden_field_tag key, value %>
<% end %>
<%= link_to bubbles_path(filter.as_params.except(:tag_ids)), class: "btn popup__item" do %>
<span class="overflow-ellipsis">Clear all</span>
<% end %>
<% Current.account.tags.order(:title).each do |tag| %>
<div class="btn popup__item">
<%= form.check_box "tag_ids[]", {
checked: filter.tags.include?(tag),
data: { action: "change->form#submit" },
include_hidden: false,
}, tag.id %>
<%= form.label "tag_ids[]", tag.hashtag, for: dom_id(tag, :filter), class: "overflow-ellipsis" %>
<%= image_tag "check.svg", aria: { hidden: true }, size: 18, class: "checked flex-item-justify-end" %>
</div>
<% end %>
<% end %>
</dialog>
</div>