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,10 +1,8 @@ |
|||||||
<%= f.govuk_check_boxes_fieldset category.to_sym, legend: { text: label, size: "s"} do %> |
<%= f.govuk_check_boxes_fieldset category.to_sym, legend: { text: label, size: "s"}, small: true, form_group: { classes: "app-filter__group" } do %> |
||||||
<div class="govuk-checkboxes govuk-checkboxes--small" data-module="govuk-checkboxes"> |
|
||||||
<% options.map do |key, option| %> |
<% options.map do |key, option| %> |
||||||
<%= f.govuk_check_box category, "#{key}", |
<%= f.govuk_check_box category, "#{key}", |
||||||
label: { text: option }, |
label: { text: option }, |
||||||
checked: filter_selected?(category, key), |
checked: filter_selected?(category, key), |
||||||
size: "s" %> |
size: "s" %> |
||||||
<% end %> |
<% end %> |
||||||
</div> |
|
||||||
<% end %> |
<% end %> |
||||||
|
Loading…
Reference in new issue