mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-11-30 05:21:08 +00:00
Tidy header for non-authenticated visitors
with the help of a login modal
This commit is contained in:
parent
ad6c860951
commit
4ed4278826
3 changed files with 141 additions and 20 deletions
|
@ -25,10 +25,26 @@ body {
|
||||||
overflow-x: auto;
|
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 {
|
.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)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -158,28 +158,14 @@
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not request.user.is_authenticated %}
|
||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
{% 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 is-narrow">
|
||||||
<form name="login" method="post" action="{% url 'login' %}?next={{ request.path }}">
|
<button class="button is-primary" type="button" data-modal-open="login-modal" aria-haspopup="dialog">{% trans "Log in" %}</button>
|
||||||
{% csrf_token %}
|
|
||||||
<div class="columns is-variable is-1">
|
|
||||||
<div class="column">
|
|
||||||
<label class="is-sr-only" for="id_localname">{% trans "Username:" %}</label>
|
|
||||||
<input type="text" name="localname" maxlength="150" class="input" required="" id="id_localname" placeholder="{% trans 'username' %}">
|
|
||||||
</div>
|
|
||||||
<div class="column">
|
|
||||||
<label class="is-sr-only" for="id_password">{% trans "Password:" %}</label>
|
|
||||||
<input type="password" name="password" maxlength="128" class="input" required="" id="id_password" placeholder="{% trans 'password' %}">
|
|
||||||
<p class="help"><a href="{% url 'password-reset' %}">{% trans "Forgot your password?" %}</a></p>
|
|
||||||
</div>
|
|
||||||
<div class="column is-narrow">
|
|
||||||
<button class="button is-primary" type="submit">{% trans "Log in" %}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
{% if site.allow_registration and request.path != '' and request.path != '/' %}
|
{% if site.allow_registration and request.path != '' and request.path != '/' %}
|
||||||
<div class="column is-narrow">
|
<div class="column is-narrow">
|
||||||
|
@ -191,7 +177,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -258,6 +244,51 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
{# Login modal #}
|
||||||
|
{% if not request.user.is_authenticated %}
|
||||||
|
<div class="modal" id="login-modal">
|
||||||
|
<div class="modal-background" data-modal-close></div>
|
||||||
|
<div class="modal-card is-thin" role="dialog" aria-modal="true" aria-labelledby="login_header" tabindex="-1">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<h1 class="modal-card-title" id="login_header">
|
||||||
|
{% trans "Log in" %}
|
||||||
|
</h1>
|
||||||
|
<button type="button" class="delete" data-modal-close aria-label="{% trans 'Close' %}"></button>
|
||||||
|
</header>
|
||||||
|
<section class="modal-card-body">
|
||||||
|
<form name="login" method="post" action="{% url 'login' %}?next={{ request.path }}" class="form" id="login-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="field">
|
||||||
|
<label class="label" for="id_localname">
|
||||||
|
{% trans "Username:" %}
|
||||||
|
</label>
|
||||||
|
<div class="control">
|
||||||
|
<input type="text" name="localname" maxlength="150" class="input" required="" id="id_localname" placeholder="{% trans 'username' %}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label" for="id_password">
|
||||||
|
{% trans "Password:" %}
|
||||||
|
</label>
|
||||||
|
<div class="control">
|
||||||
|
<input type="password" name="password" maxlength="128" class="input" required="" id="id_password" placeholder="{% trans 'password' %}">
|
||||||
|
</div>
|
||||||
|
<p class="help">
|
||||||
|
<a href="{% url 'password-reset' %}">{% trans "Forgot your password?" %}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<button class="button is-primary" type="submit" form="login-form">
|
||||||
|
{% trans "Log in" %}
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
<button type="button" data-modal-close class="modal-close is-large" aria-label="{% trans 'Close' %}"></a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var csrf_token = '{{ csrf_token }}';
|
var csrf_token = '{{ csrf_token }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue