Merge pull request #1633 from joachimesque/tidy-header

Front-end: New modal component + header alignment
This commit is contained in:
Mouse Reeve 2021-12-28 16:24:27 -08:00 committed by GitHub
commit 4b3d2e87a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 163 additions and 14 deletions

View file

@ -8,6 +8,41 @@ body {
flex-direction: column; flex-direction: column;
} }
button {
border: none;
margin: 0;
padding: 0;
width: auto;
overflow: visible;
background: transparent;
/* inherit font, color & alignment from ancestor */
color: inherit;
font: inherit;
text-align: inherit;
/* Normalize `line-height`. Cannot be changed from `normal` in Firefox 4+. */
line-height: normal;
/* Corrects font smoothing for webkit */
-webkit-font-smoothing: inherit;
-moz-osx-font-smoothing: inherit;
/* Corrects inability to style clickable `input` types in iOS */
-webkit-appearance: none;
}
button::-moz-focus-inner {
/* Remove excess padding and border in Firefox 4+ */
border: 0;
padding: 0;
}
/* Better accessibility for keyboard users */
*:focus-visible {
outline-style: auto !important;
}
.image { .image {
overflow: hidden; overflow: hidden;
} }
@ -29,10 +64,30 @@ body {
overflow-x: auto; overflow-x: auto;
} }
/* stylelint-disable no-descending-specificity */
.modal-card:focus {
outline-style: auto;
}
.modal-card:focus:not(:focus-visible) {
outline-style: initial;
}
.modal-card:focus-visible {
outline-style: auto;
}
/* stylelint-enable no-descending-specificity */
.modal-card.is-fullwidth { .modal-card.is-fullwidth {
min-width: 75% !important; min-width: 75% !important;
} }
@media only screen and (min-width: 769px) {
.modal-card.is-thin {
width: 350px !important;
}
}
.modal-card-body { .modal-card-body {
max-height: 70vh; max-height: 70vh;
} }

View file

@ -45,6 +45,12 @@ let BookWyrm = new class {
'change', 'change',
this.disableIfTooLarge.bind(this) this.disableIfTooLarge.bind(this)
)); ));
document.querySelectorAll('button[data-modal-open]')
.forEach(node => node.addEventListener(
'click',
this.handleModalButton.bind(this)
));
document.querySelectorAll('[data-duplicate]') document.querySelectorAll('[data-duplicate]')
.forEach(node => node.addEventListener( .forEach(node => node.addEventListener(
@ -420,6 +426,97 @@ let BookWyrm = new class {
} }
} }
/**
* Handle the modal component.
*
* @param {Event} event - Event fired by an element
* with the `data-modal-open` attribute
* pointing to a modal by its id.
* @return {undefined}
*
* See https://github.com/bookwyrm-social/bookwyrm/pull/1633
* for information about using the modal.
*/
handleModalButton(event) {
const modalButton = event.currentTarget;
const targetModalId = modalButton.dataset.modalOpen;
const htmlElement = document.querySelector('html');
const modal = document.getElementById(targetModalId);
if (!modal) {
return;
}
// 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) {
if (event.key !== 'Tab') {
return;
}
const focusableEls = event.currentTarget.querySelectorAll(
[
'a[href]:not([disabled])',
'button:not([disabled])',
'textarea:not([disabled])',
'input:not([type="hidden"]):not([disabled])',
'select:not([disabled])',
'details:not([disabled])',
'[tabindex]:not([tabindex="-1"]):not([disabled])'
].join(',')
);
const firstFocusableEl = focusableEls[0];
const lastFocusableEl = focusableEls[focusableEls.length - 1];
if (event.shiftKey ) /* Shift + tab */ {
if (document.activeElement === firstFocusableEl) {
lastFocusableEl.focus();
event.preventDefault();
}
} else /* Tab */ {
if (document.activeElement === lastFocusableEl) {
firstFocusableEl.focus();
event.preventDefault();
}
}
}
// Open modal
handleModalOpen(modal);
}
/** /**
* Display pop up window. * Display pop up window.
* *

View file

@ -38,7 +38,7 @@
<a class="navbar-item" href="/"> <a class="navbar-item" href="/">
<img class="image logo" src="{% if site.logo_small %}{% get_media_prefix %}{{ site.logo_small }}{% else %}{% static "images/logo-small.png" %}{% endif %}" alt="{% blocktrans with site_name=site.name %}{{ site_name }} home page{% endblocktrans %}"> <img class="image logo" src="{% if site.logo_small %}{% get_media_prefix %}{{ site.logo_small }}{% else %}{% static "images/logo-small.png" %}{% endif %}" alt="{% blocktrans with site_name=site.name %}{{ site_name }} home page{% endblocktrans %}">
</a> </a>
<form class="navbar-item column" action="{% url 'search' %}"> <form class="navbar-item column is-align-items-start pt-5" action="{% url 'search' %}">
<div class="field has-addons"> <div class="field has-addons">
<div class="control"> <div class="control">
{% if user.is_authenticated %} {% if user.is_authenticated %}
@ -58,25 +58,22 @@
</div> </div>
</form> </form>
<div role="button" tabindex="0" class="navbar-burger pulldown-menu" data-controls="main_nav" aria-expanded="false"> <button type="button" tabindex="0" class="navbar-burger pulldown-menu my-4" data-controls="main_nav" aria-expanded="false">
<div class="navbar-item mt-3"> <i class="icon icon-dots-three-vertical" aria-hidden="true"></i>
<div class="icon icon-dots-three-vertical" title="{% trans 'Main navigation menu' %}"> <span class="is-sr-only">{% trans "Main navigation menu" %}</span>
<span class="is-sr-only">{% trans "Main navigation menu" %}</span> </button>
</div>
</div>
</div>
</div> </div>
<div class="navbar-menu" id="main_nav"> <div class="navbar-menu" id="main_nav">
<div class="navbar-start"> <div class="navbar-start">
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<a href="/#feed" class="navbar-item"> <a href="/#feed" class="navbar-item mt-3 py-0">
{% trans "Feed" %} {% trans "Feed" %}
</a> </a>
<a href="{% url 'lists' %}" class="navbar-item"> <a href="{% url 'lists' %}" class="navbar-item mt-3 py-0">
{% trans "Lists" %} {% trans "Lists" %}
</a> </a>
<a href="{% url 'discover' %}" class="navbar-item"> <a href="{% url 'discover' %}" class="navbar-item mt-3 py-0">
{% trans "Discover" %} {% trans "Discover" %}
</a> </a>
{% endif %} {% endif %}
@ -84,7 +81,7 @@
<div class="navbar-end"> <div class="navbar-end">
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="navbar-item has-dropdown is-hoverable"> <div class="navbar-item mt-3 py-0 has-dropdown is-hoverable">
<a <a
href="{{ request.user.local_path }}" href="{{ request.user.local_path }}"
class="navbar-link pulldown-menu" class="navbar-link pulldown-menu"
@ -143,7 +140,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="navbar-item"> <div class="navbar-item mt-3 py-0">
<a href="{% url 'notifications' %}" class="tags has-addons"> <a href="{% url 'notifications' %}" class="tags has-addons">
<span class="tag is-medium"> <span class="tag is-medium">
<span class="icon icon-bell" title="{% trans 'Notifications' %}"> <span class="icon icon-bell" title="{% trans 'Notifications' %}">
@ -161,7 +158,7 @@
</a> </a>
</div> </div>
{% else %} {% else %}
<div class="navbar-item"> <div class="navbar-item pt-5 pb-0">
{% if request.path != '/login' and request.path != '/login/' %} {% if request.path != '/login' and request.path != '/login/' %}
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">