From 4ed4278826d3e88bc544f22159aa6bb0b16fbe75 Mon Sep 17 00:00:00 2001 From: Joachim Date: Sat, 27 Nov 2021 19:18:20 +0100 Subject: [PATCH] Tidy header for non-authenticated visitors with the help of a login modal --- bookwyrm/static/css/bookwyrm.css | 16 +++++++ bookwyrm/static/js/bookwyrm.js | 74 ++++++++++++++++++++++++++++++++ bookwyrm/templates/layout.html | 71 +++++++++++++++++++++--------- 3 files changed, 141 insertions(+), 20 deletions(-) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 0d280fd53..81f0cf1a8 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -25,10 +25,26 @@ body { overflow-x: auto; } +.modal-card:focus { + outline-style: auto; +} +.modal-card:focus:not(:focus-visible) { + outline-style: initial; +} +.modal-card:focus-visible { + outline-style: auto; +} + .modal-card.is-fullwidth { min-width: 75% !important; } +@media only screen and (min-width: 769px) { + .modal-card.is-thin { + width: 350px !important; + } +} + .modal-card-body { max-height: 70vh; } diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 2d5b88adc..5f062f786 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -45,6 +45,12 @@ let BookWyrm = new class { 'change', this.disableIfTooLarge.bind(this) )); + + document.querySelectorAll('button[data-modal-open]') + .forEach(node => node.addEventListener( + 'click', + this.handleModalButton.bind(this) + )); } /** @@ -368,4 +374,72 @@ let BookWyrm = new class { ); } } + + handleModalButton(element) { + const modalButton = element.currentTarget; + const targetModalId = modalButton.dataset.modalOpen; + const htmlElement = document.querySelector('html'); + + // Helper functions + function handleModalOpen(modalElement) { + htmlElement.classList.add('is-clipped'); + modalElement.classList.add('is-active'); + modalElement.getElementsByClassName('modal-card')[0].focus(); + + const closeButtons = modalElement.querySelectorAll("[data-modal-close]"); + closeButtons.forEach((button) => { + button.addEventListener( + 'click', + function() { handleModalClose(modalElement) }, + ); + }); + + document.addEventListener( + 'keydown', + function(event) { + if (event.key === 'Escape') { + handleModalClose(modalElement); + } + }, + ); + + modalElement.addEventListener('keydown', handleFocusTrap) + } + + function handleModalClose(modalElement) { + modalElement.removeEventListener('keydown', handleFocusTrap) + htmlElement.classList.remove('is-clipped'); + modalElement.classList.remove('is-active'); + modalButton.focus(); + } + + function handleFocusTrap(event) { + const focusableEls = event.currentTarget.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'); + const firstFocusableEl = focusableEls[0]; + const lastFocusableEl = focusableEls[focusableEls.length - 1]; + + if (event.key !== 'Tab') { + return; + } + + if (event.shiftKey ) /* shift + tab */ { + if (document.activeElement === firstFocusableEl) { + lastFocusableEl.focus(); + event.preventDefault(); + } + } else /* tab */ { + if (document.activeElement === lastFocusableEl) { + firstFocusableEl.focus(); + event.preventDefault(); + } + } + } + + const modal = document.getElementById(targetModalId); + if (modal) { + // Open the modal + handleModalOpen(modal); + } + } + }(); diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index f2d04f961..4a7457dca 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -158,28 +158,14 @@ {% endwith %} - {% else %} + {% endif %} + + {% if not request.user.is_authenticated %} @@ -258,6 +244,51 @@ +{# Login modal #} +{% if not request.user.is_authenticated %} + +{% endif %} +