Browse Source
Ensure filters appear correctly, and that filter toggle behaves as expected (and across viewports)pull/476/head
Paul Robert Lloyd
3 years ago
10 changed files with 233 additions and 111 deletions
@ -1,16 +0,0 @@
|
||||
import { Controller } from "@hotwired/stimulus"; |
||||
|
||||
export default class extends Controller { |
||||
toggleFilter() { |
||||
let filter_panel = document.getElementById("filter-panel"); |
||||
let toggle_filter_button = document.getElementById("toggle-filter-button"); |
||||
|
||||
if (filter_panel.style.display === "none" || !filter_panel.style.display) { |
||||
filter_panel.style.display = "block"; |
||||
toggle_filter_button.innerText = "Hide filters"; |
||||
} else { |
||||
filter_panel.style.display = "none"; |
||||
toggle_filter_button.innerText = "Show filters"; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
import { Controller } from "@hotwired/stimulus"; |
||||
import { FilterToggle } from "../modules/filter_toggle.js" |
||||
|
||||
export default class extends Controller { |
||||
connect() { |
||||
const filterToggle = new FilterToggle({ |
||||
bigModeMediaQuery: '(min-width: 48.0625em)', |
||||
closeButton: { |
||||
container: this.element.querySelector('.app-filter__header'), |
||||
text: 'Close' |
||||
}, |
||||
filter: { |
||||
container: this.element.querySelector('.app-filter-layout__filter') |
||||
}, |
||||
startHidden: false, |
||||
toggleButton: { |
||||
container: this.element.querySelector('.app-filter-toggle'), |
||||
showText: 'Show filters', |
||||
hideText: 'Hide filters', |
||||
classes: 'govuk-button--secondary' |
||||
} |
||||
}) |
||||
|
||||
filterToggle.init() |
||||
} |
||||
} |
@ -0,0 +1,112 @@
|
||||
export class FilterToggle { |
||||
constructor (options) { |
||||
this.options = options |
||||
this.container = this.options.toggleButton.container |
||||
} |
||||
|
||||
setupResponsiveChecks () { |
||||
this.mq = window.matchMedia(this.options.bigModeMediaQuery) |
||||
this.mq.addListener(this.checkMode.bind(this)) |
||||
this.checkMode(this.mq) |
||||
} |
||||
|
||||
checkMode (mq) { |
||||
if (mq.matches) { |
||||
this.enableBigMode() |
||||
} else { |
||||
this.enableSmallMode() |
||||
} |
||||
} |
||||
|
||||
enableBigMode () { |
||||
this.showMenu() |
||||
this.removeMenuButton() |
||||
this.removeCloseButton() |
||||
} |
||||
|
||||
enableSmallMode () { |
||||
this.options.filter.container.setAttribute("tabindex", "-1") |
||||
this.hideMenu() |
||||
this.addMenuButton() |
||||
this.addCloseButton() |
||||
} |
||||
|
||||
addCloseButton () { |
||||
if (this.options.closeButton) { |
||||
this.closeButton = document.createElement("button") |
||||
this.closeButton.classList.add("app-filter__close") |
||||
this.closeButton.innerText = this.options.closeButton.text |
||||
this.closeButton.type = 'button' |
||||
this.closeButton.addEventListener('click', this.onCloseClick.bind(this)) |
||||
|
||||
this.options.closeButton.container.append(this.closeButton) |
||||
} |
||||
} |
||||
|
||||
onCloseClick () { |
||||
this.hideMenu() |
||||
this.menuButton.focus() |
||||
} |
||||
|
||||
removeCloseButton () { |
||||
if (this.closeButton) { |
||||
this.closeButton.remove() |
||||
this.closeButton = null |
||||
} |
||||
} |
||||
|
||||
addMenuButton () { |
||||
this.menuButton = document.createElement("button") |
||||
this.menuButton.setAttribute("aria-expanded", "false") |
||||
this.menuButton.setAttribute("aria-has-popup", "true") |
||||
this.menuButton.classList.add("govuk-button", this.options.toggleButton.classes, "app-filter-toggle__button") |
||||
this.menuButton.innerText = this.options.toggleButton.showText |
||||
this.menuButton.type = "button" |
||||
this.menuButton.addEventListener("click", this.onMenuButtonClick.bind(this)) |
||||
|
||||
this.options.toggleButton.container.prepend(this.menuButton) |
||||
} |
||||
|
||||
removeMenuButton () { |
||||
if (this.menuButton) { |
||||
this.menuButton.remove() |
||||
this.menuButton = null |
||||
} |
||||
} |
||||
|
||||
hideMenu () { |
||||
if (this.menuButton) { |
||||
this.menuButton.setAttribute("aria-expanded", "false") |
||||
this.menuButton.innerText = this.options.toggleButton.showText |
||||
} |
||||
this.options.filter.container.setAttribute("hidden", true) |
||||
} |
||||
|
||||
showMenu () { |
||||
if (this.menuButton) { |
||||
this.menuButton.setAttribute("aria-expanded", "true") |
||||
this.menuButton.innerText = this.options.toggleButton.hideText |
||||
} |
||||
this.options.filter.container.removeAttribute("hidden") |
||||
} |
||||
|
||||
onMenuButtonClick () { |
||||
this.toggle() |
||||
} |
||||
|
||||
toggle () { |
||||
if (this.options.filter.container.hidden) { |
||||
this.showMenu() |
||||
this.options.filter.container.focus() |
||||
} else { |
||||
this.hideMenu() |
||||
} |
||||
} |
||||
|
||||
init () { |
||||
this.setupResponsiveChecks() |
||||
if (this.options.startHidden) { |
||||
this.hideMenu() |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,42 @@
|
||||
.app-filter-layout { |
||||
@include govuk-clearfix; |
||||
} |
||||
|
||||
.app-filter-layout__filter { |
||||
@include govuk-media-query(desktop) { |
||||
float: left; |
||||
min-width: govuk-grid-width("one-quarter"); |
||||
} |
||||
} |
||||
|
||||
.js-enabled .app-filter-layout__filter { |
||||
outline: 0 none; |
||||
|
||||
@include govuk-media-query($until: desktop) { |
||||
background-color: govuk-colour("light-grey"); |
||||
bottom: govuk-spacing(1); |
||||
border: 1px solid govuk-colour("mid-grey"); |
||||
max-width: 310px; |
||||
min-width: 260px; |
||||
width: 100%; |
||||
overflow-y: scroll; |
||||
position: fixed; |
||||
right: govuk-spacing(1); |
||||
top: govuk-spacing(1); |
||||
z-index: 100; |
||||
|
||||
&:focus { |
||||
outline: $govuk-focus-width solid $govuk-focus-colour; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.app-filter-layout__content { |
||||
@include govuk-media-query(desktop) { |
||||
float: right; |
||||
max-width: calc( |
||||
#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)} |
||||
); |
||||
width: 100%; |
||||
} |
||||
} |
@ -1,25 +1,16 @@
|
||||
<div class="app-filter-layout__filter" tabindex="-1" id="filter-panel"> |
||||
<div class="app-filter" > |
||||
<div class="app-filter-layout__filter"> |
||||
<div class="app-filter"> |
||||
<div class="app-filter__header"> |
||||
<h2 class="govuk-heading-m">Filters</h2> |
||||
<button |
||||
class="app-filter__close" |
||||
type="button" |
||||
data-controller="filter" |
||||
data-action="click->filter#toggleFilter"> |
||||
Close |
||||
</button> |
||||
</div> |
||||
<div class="app-filter__content"> |
||||
<div class="govuk-form-group app-filter__group"> |
||||
<%= form_with url: "/logs", html: { method: :get } do |f| %> |
||||
<% years = {"2021": "2021/22", "2022": "2022/23"} %> |
||||
<%= render partial: "filters/checkbox_filter", locals: { f: f, options: years, label: "Collection year", category: "years" } %> |
||||
<%= render partial: "filters/checkbox_filter", locals: { f: f, options: status_filters, label: "Status", category: "status" } %> |
||||
<%= render partial: "filters/checkbox_filter", locals: { f: f, options: {"all": "All", "yours": "Yours"}, label: "Logs", category: "user" } %> |
||||
<%= f.govuk_submit "Apply filters", class: "govuk-!-margin-top-4" %> |
||||
<%= f.govuk_submit "Apply filters", class: "govuk-!-margin-bottom-0" %> |
||||
<% end %> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
@ -1,10 +1,8 @@
|
||||
<%= f.govuk_check_boxes_fieldset category.to_sym, legend: { text: label, size: "s"} do %> |
||||
<div class="govuk-checkboxes govuk-checkboxes--small" data-module="govuk-checkboxes"> |
||||
<%= f.govuk_check_boxes_fieldset category.to_sym, legend: { text: label, size: "s"}, small: true, form_group: { classes: "app-filter__group" } do %> |
||||
<% options.map do |key, option| %> |
||||
<%= f.govuk_check_box category, "#{key}", |
||||
label: { text: option }, |
||||
checked: filter_selected?(category, key), |
||||
size: "s" %> |
||||
<% end %> |
||||
</div> |
||||
<% end %> |
||||
|
Loading…
Reference in new issue