Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ GEM
logger (~> 1.5)
concurrent-ruby (1.3.7)
connection_pool (3.0.2)
crass (1.0.6)
crass (1.0.7)
date (3.5.1)
debug (1.11.1)
irb (~> 1.10)
Expand Down Expand Up @@ -498,7 +498,7 @@ CHECKSUMS
childprocess (5.1.0) sha256=9a8d484be2fd4096a0e90a0cd3e449a05bc3aa33f8ac9e4d6dcef6ac1455b6ec
concurrent-ruby (1.3.7) sha256=4412caec3a5ea2e5fdc52076724c071a81f2c0593d83b2ac8cbb8ca63b3151b0
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
crass (1.0.7) sha256=94868719948664c89ddcaf0a37c65048413dfcb1c869470a5f7a7ceb5390b295
date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6
docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
Expand Down
74 changes: 74 additions & 0 deletions app/javascript/controllers/chip_overflow_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Controller } from "@hotwired/stimulus"

// Collapses a wrapping row of chips down to a fixed number of rows, with a
// toggle button at the end of the last visible row to reveal the rest.
export default class extends Controller {
static targets = ["chip", "button"]
static values = { rows: { type: Number, default: 2 }, expanded: Boolean }

connect() {
// Default to expanded when a chip in this category is already selected, so
// the active preference is visible without having to click "Show more".
if (this.chipTargets.some((chip) => chip.querySelector("input")?.checked)) {
this.expandedValue = true
}
this.onResize = () => this.layout()
this.resizeObserver = new ResizeObserver(this.onResize)
this.resizeObserver.observe(this.element)
window.addEventListener("resize", this.onResize)
this.layout()
}

disconnect() {
if (this.resizeObserver) this.resizeObserver.disconnect()
window.removeEventListener("resize", this.onResize)
}

toggle() {
this.expandedValue = !this.expandedValue
this.layout()
}

layout() {
if (!this.hasButtonTarget) return

// Reset: reveal everything so positions can be measured.
this.chipTargets.forEach((chip) => (chip.hidden = false))
this.buttonTarget.hidden = true

if (this.expandedValue) {
this.buttonTarget.textContent = "Show less"
this.buttonTarget.hidden = false
return
}

const tops = [...new Set(this.chipTargets.map((chip) => Math.round(chip.offsetTop)))].sort(
(a, b) => a - b,
)

// Already fits within the row budget — nothing to collapse.
if (tops.length <= this.rowsValue) return

const cutoff = tops[this.rowsValue - 1]
let hidden = 0
this.chipTargets.forEach((chip) => {
if (Math.round(chip.offsetTop) > cutoff) {
chip.hidden = true
hidden++
}
})

// Reveal the button at the end of the last visible row. If it wrapped past
// the cutoff, hide trailing chips until it fits.
this.buttonTarget.hidden = false
const visibleChips = this.chipTargets.filter((chip) => !chip.hidden)
let i = visibleChips.length - 1
while (Math.round(this.buttonTarget.offsetTop) > cutoff && i >= 0) {
visibleChips[i].hidden = true
hidden++
i--
}

this.buttonTarget.textContent = `Show more (+${hidden})`
}
}
6 changes: 4 additions & 2 deletions app/views/scenarios/_additional_preferences.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@
<% roots = roots_by_type[klass_name] %>
<% next if roots.blank? %>
<p class="mt-4 text-xs font-medium uppercase tracking-wide text-ink-faint"><%= klass_name.constantize.tab_label %></p>
<div class="mt-2 flex flex-wrap gap-2">
<div class="mt-2 flex flex-wrap gap-2" data-controller="chip-overflow" data-chip-overflow-rows-value="2">
<% roots.each do |cat| %>
<label class="inline-block cursor-pointer rounded-full border border-line bg-surface px-3 py-1 text-sm text-ink-soft transition hover:bg-canvas has-[:checked]:border-accent has-[:checked]:bg-accent has-[:checked]:text-white">
<label data-chip-overflow-target="chip" class="inline-block cursor-pointer rounded-full border border-line bg-surface px-3 py-1 text-sm text-ink-soft transition hover:bg-canvas has-[:checked]:border-accent has-[:checked]:bg-accent has-[:checked]:text-white">
<%= check_box_tag "allocation[preference_category_ids][]", cat.id, selected_ids.include?(cat.id),
id: "pref_#{suffix}_#{cat.id}", class: "sr-only" %>
<%= cat.name %>
</label>
<% end %>
<button type="button" data-chip-overflow-target="button" data-action="chip-overflow#toggle"
class="hidden inline-flex items-center cursor-pointer px-1 text-sm font-medium text-accent hover:underline"></button>
</div>
<% end %>
</div>
Expand Down
Loading