Skip to content

Commit 3327a02

Browse files
authored
Interface improvements (#255)
This ships some improvements, including: * Keep notifications while navigating. * Keep notifications visible during mouse interactions. * Replace Symfony toolbar with latest AJAX info. * Use a condensed layout to improve predictability of the design.
1 parent 3ecfc45 commit 3327a02

File tree

12 files changed

+62
-23
lines changed

12 files changed

+62
-23
lines changed

assets/js/Common/HttpClient.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
class HttpClient {
22
constructor() {
3-
this.onError = (response) => {
4-
};
3+
this.onError = () => true;
54
}
65

76
/**
87
* @param {String} url
98
* @returns {Promise}
109
*/
1110
async get(url) {
12-
const response = await fetch(url, {
13-
headers: {'X-Requested-With': 'XMLHttpRequest'}
14-
});
11+
const response = await fetch(url);
1512
const json = await response.json();
1613

1714
if (response.status >= 200 && response.status < 300) return json;
@@ -28,7 +25,6 @@ class HttpClient {
2825
async post(url, data) {
2926
const response = await fetch(url, {
3027
method: 'POST',
31-
headers: {'X-Requested-With': 'XMLHttpRequest'},
3228
body: new URLSearchParams(data)
3329
});
3430
const json = await response.json();

assets/js/Common/NotificationList.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,16 @@ customElements.define('notification-list', class extends HTMLElement {
2828

2929
this.insertBefore(messageNode, this.childNodes[0]);
3030

31-
await new Promise(resolve => setTimeout(resolve, timeout));
32-
messageNode.addEventListener('animationend', () => this.removeChild(messageNode));
33-
messageNode.classList.add('gp-fadeout');
31+
let handle = this._scheduleRemoval(messageNode, timeout);
32+
33+
messageNode.addEventListener('mouseenter', () => clearTimeout(handle));
34+
messageNode.addEventListener('mouseleave', () => handle = this._scheduleRemoval(messageNode, timeout));
35+
}
36+
37+
_scheduleRemoval = (messageNode, timeout) => {
38+
return setTimeout(() => {
39+
messageNode.addEventListener('animationend', () => this.removeChild(messageNode));
40+
messageNode.classList.add('gp-fadeout')
41+
}, timeout);
3442
}
3543
});

assets/js/app.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ import '@tabler/core/dist/css/tabler.min.css'
44
import '@tabler/core/dist/js/tabler.min.js'
55
import '../css/app.css'
66

7+
window.fetch = (fetch => async (resource, options = {}) => {
8+
return fetch(
9+
resource,
10+
{...options, headers: {...(options.headers || {}), 'X-Requested-With': 'XMLHttpRequest'}}
11+
);
12+
})(window.fetch);
13+
714
window.app = {
815
navigate: url => top.location.href = url,
916
loadElements: node => Promise.allSettled([...node.querySelectorAll(':not(:defined)')]
@@ -22,6 +29,7 @@ window.app = {
2229
peInit() {
2330
if (!window.pe) return window.addEventListener('pe:init', window.app.peInit);
2431
window.app.navigate = window.pe.navigate;
32+
window.pe.selectSource = window.pe.selectTarget = d => d.querySelector('[data-page-content]');
2533
}
2634
}
2735

assets/js/pe.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
function render(oldDocument, newDocument) {
22
oldDocument.title = newDocument.title || oldDocument.title;
3-
oldDocument.body.replaceWith(newDocument.body);
4-
[...oldDocument.body.getElementsByTagName('script')].forEach(n => {
3+
const sourceNode = window.pe.selectSource(newDocument);
4+
window.pe.selectTarget(oldDocument).replaceWith(sourceNode);
5+
[...sourceNode.getElementsByTagName('script')].forEach(n => {
56
const s = oldDocument.createElement('script');
67
s.innerHTML = n.innerHTML;
78
[...n.attributes].forEach(a => s.setAttribute(a.nodeName, a.nodeValue));
@@ -96,7 +97,13 @@ async function submit(form) {
9697
}
9798
}
9899

99-
window.pe = {navigate: url => navigate(url, true), submit, abortController: new AbortController()};
100+
window.pe = {
101+
navigate: url => navigate(url, true),
102+
submit,
103+
abortController: new AbortController(),
104+
selectSource: d => d.body,
105+
selectTarget: d => d.body
106+
};
100107

101108
window.addEventListener('popstate', () => navigate(top.location.href, false));
102109
document.addEventListener('click', e => {

config/web-interface/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ security:
2828
- 'web-interface.security.arrival_authenticator'
2929
logout:
3030
path: /logout
31+
32+
when@dev:
33+
services:
34+
Gaming\WebInterface\Infrastructure\Symfony\ReplaceSymfonyToolbar:
35+
tags: [{ name: kernel.event_listener, event: kernel.response }]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Gaming\WebInterface\Infrastructure\Symfony;
6+
7+
use Symfony\Component\HttpKernel\Event\ResponseEvent;
8+
9+
final class ReplaceSymfonyToolbar
10+
{
11+
public function onKernelResponse(ResponseEvent $event): void
12+
{
13+
if ($event->getRequest()->isXmlHttpRequest()) {
14+
$event->getResponse()->headers->set('Symfony-Debug-Toolbar-Replace', '1');
15+
}
16+
}
17+
}

src/WebInterface/Presentation/Http/View/game.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends '@web-interface/layout/fluid.html.twig' %}
1+
{% extends '@web-interface/layout/condensed.html.twig' %}
22

33
{% set page_title = 'Anonymous vs. Anonymous' %}
44

src/WebInterface/Presentation/Http/View/layout/base.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<script type="module" src="{{ asset('js/pe.js') }}"></script>
1616
<script>window.matchMedia("(prefers-color-scheme:dark)").matches && document.documentElement.setAttribute('data-bs-theme', 'dark');</script>
1717
</head>
18-
<body class="{{ body_class is defined ? body_class : 'layout-fluid' }}">
18+
<body>
1919
<notification-list></notification-list>
2020
{% block body %}{% endblock %}
2121
</body>

src/WebInterface/Presentation/Http/View/layout/center-tight.html.twig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
{% extends '@web-interface/layout/base.html.twig' %}
22

3-
{% set body_class = 'd-flex flex-column' %}
4-
53
{% block body %}
6-
<div class="page page-center">
4+
<div class="page page-center" data-page-content>
75
<div class="container container-tight">
86
<p class="text-center fw-medium my-5">
97
<a href="{{ path('lobby') }}" class="link-secondary navbar-brand-autodark text-decoration-none">

src/WebInterface/Presentation/Http/View/layout/fluid.html.twig renamed to src/WebInterface/Presentation/Http/View/layout/condensed.html.twig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{% extends '@web-interface/layout/base.html.twig' %}
22

33
{% block body %}
4-
<div class="page">
4+
<div class="page" data-page-content>
55
<header class="navbar navbar-expand d-print-none sticky-top">
6-
<div class="container-xl">
6+
<div class="container-xxl">
77
<div class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-lg-1">
88
<a href="{{ path('lobby') }}">
99
<img src="{{ asset('img/logo.png') }}"
@@ -99,13 +99,13 @@
9999
</header>
100100
<div class="page-wrapper">
101101
<div class="page-body">
102-
<div class="container">
102+
<div class="container-xxl">
103103
{% block content %}{% endblock %}
104104
</div>
105105
</div>
106106
</div>
107107
<footer class="footer footer-transparent d-print-none">
108-
<div class="container-xl">
108+
<div class="container-xxl">
109109
<div class="row text-center align-items-center flex-row-reverse">
110110
<div class="col-lg-auto ms-lg-auto">
111111
<ul class="list-inline list-inline-dots mb-0">

0 commit comments

Comments
 (0)