forked from mirrors/bookwyrm
Merge pull request #1633 from joachimesque/tidy-header
Front-end: New modal component + header alignment
This commit is contained in:
commit
4b3d2e87a6
3 changed files with 163 additions and 14 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Loading…
Reference in a new issue