mirror of
https://github.com/sigmasternchen/mobmash.click
synced 2025-03-15 08:09:02 +00:00
feat: AJAX loading with loading animation
This commit is contained in:
parent
55394f857b
commit
f8bff80e3d
10 changed files with 133 additions and 34 deletions
BIN
html/images/gras.png
Normal file
BIN
html/images/gras.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -9,16 +9,26 @@ function renderChoice(): void {
|
||||||
[$left, $right] = [$_SESSION["left"], $_SESSION["right"]];
|
[$left, $right] = [$_SESSION["left"], $_SESSION["right"]];
|
||||||
|
|
||||||
$csrfToken = $_SESSION["csrfToken"];
|
$csrfToken = $_SESSION["csrfToken"];
|
||||||
$title = "Test";
|
|
||||||
$content = function() use ($left, $right, $csrfToken) {
|
|
||||||
include __DIR__ . "/../view/fragments/mobSelection.php";
|
|
||||||
};
|
|
||||||
|
|
||||||
include __DIR__ . "/../view/layout.php";
|
if (isset($_GET["ajax"])) {
|
||||||
|
include __DIR__ . "/../view/fragments/mobSelection.php";
|
||||||
|
} else {
|
||||||
|
$title = "Test";
|
||||||
|
$content = function() use ($left, $right, $csrfToken) {
|
||||||
|
include __DIR__ . "/../view/fragments/mobSelection.php";
|
||||||
|
};
|
||||||
|
|
||||||
|
include __DIR__ . "/../view/layout.php";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload(): void {
|
function reload(): void {
|
||||||
header("LOCATION: /");
|
if (isset($_GET["ajax"])) {
|
||||||
|
header("LOCATION: ?ajax");
|
||||||
|
} else {
|
||||||
|
header("LOCATION: /");
|
||||||
|
}
|
||||||
|
|
||||||
http_send_status(303);
|
http_send_status(303);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,44 @@ h1 {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.separator div {
|
.separator .or, .separator .spinner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transform: translate(0%, -50%);
|
transform: translate(0%, -50%);
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.separator .spinner {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-preload .spinner {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.img-preload .or {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator .spinner img {
|
||||||
|
animation-name: spinner;
|
||||||
|
animation-duration: 1s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-timing-function: cubic-bezier(0.68, -0.6, 0.32, 1.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.mob {
|
.mob {
|
||||||
width: 40vw;
|
width: 40vw;
|
||||||
height: 42vw;
|
height: 42vw;
|
||||||
|
|
5
resources/js/htmx.js
Normal file
5
resources/js/htmx.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import htmx from 'htmx.org';
|
||||||
|
|
||||||
|
console.log("htmx loaded");
|
||||||
|
//htmx.logAll();
|
||||||
|
window.htmx = htmx;
|
48
resources/js/img-preload.ext.js
Normal file
48
resources/js/img-preload.ext.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import htmx from 'htmx.org';
|
||||||
|
|
||||||
|
console.log("module loaded");
|
||||||
|
|
||||||
|
htmx.defineExtension('img-preload', {
|
||||||
|
onEvent: (name, event) => {
|
||||||
|
if (event.target.getAttribute("hx-ext") !== "img-preload") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spinner = [...document.querySelectorAll(
|
||||||
|
event.target.getAttribute("data-preload-spinner")
|
||||||
|
?? ".img-preload"
|
||||||
|
)];
|
||||||
|
|
||||||
|
switch (name) {
|
||||||
|
case 'htmx:trigger':
|
||||||
|
spinner.forEach(s => s.classList.add("img-preload"));
|
||||||
|
break;
|
||||||
|
case 'htmx:beforeOnLoad':
|
||||||
|
event.detail.shouldSwap = false;
|
||||||
|
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(event.detail.xhr.response, 'text/html');
|
||||||
|
const imagePromises = [...doc.getElementsByTagName('img')]
|
||||||
|
.map(img => img.src)
|
||||||
|
.map(src => new Promise((resolve, reject) => {
|
||||||
|
const image = new Image();
|
||||||
|
image.onload = resolve;
|
||||||
|
image.onerror = reject;
|
||||||
|
image.src = src;
|
||||||
|
}));
|
||||||
|
|
||||||
|
Promise.all(imagePromises)
|
||||||
|
.then(() => {
|
||||||
|
spinner.forEach(s => s.classList.remove("img-preload"));
|
||||||
|
htmx.swap(event.detail.target, event.detail.xhr.response, {
|
||||||
|
swapStyle: "outerHTML",
|
||||||
|
transition: true,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading images:', error);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,3 +1,2 @@
|
||||||
import htmx from 'htmx.org';
|
import './htmx';
|
||||||
|
import './img-preload.ext';
|
||||||
window.htmx = htmx;
|
|
||||||
|
|
8
resources/js/package-lock.json
generated
8
resources/js/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"htmx.org": "^1.9.12"
|
"htmx.org": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "0.23.0"
|
"esbuild": "0.23.0"
|
||||||
|
@ -439,9 +439,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/htmx.org": {
|
"node_modules/htmx.org": {
|
||||||
"version": "1.9.12",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.12.tgz",
|
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.1.tgz",
|
||||||
"integrity": "sha512-VZAohXyF7xPGS52IM8d1T1283y+X4D+Owf3qY1NZ9RuBypyu9l8cGsxUMAG5fEAb/DhT7rDoJ9Hpu5/HxFD3cw=="
|
"integrity": "sha512-wO/rWlveSLD2mzRS9Em0v5hlsi6r21iUvaS17GPMgehBbM7eoQmqGQCkscsM67poF24zONgq3gQv+q/cgCHn2w=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"htmx.org": "^1.9.12"
|
"htmx.org": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "0.23.0"
|
"esbuild": "0.23.0"
|
||||||
|
|
|
@ -3,9 +3,11 @@
|
||||||
$mob ??= [];
|
$mob ??= [];
|
||||||
$csrfToken ??= "";
|
$csrfToken ??= "";
|
||||||
?>
|
?>
|
||||||
<form action="?<?= $side ?>" method="POST" name="<?= $side ?>" id="form-<?= $side ?>">
|
<form action="?<?= $side ?>" method="POST" name="<?= $side ?>" id="form-<?= $side ?>"
|
||||||
|
hx-post="?<?= $side ?>&ajax" hx-target=".choice" hx-swap="outerHTML"
|
||||||
|
hx-ext="img-preload" data-preload-spinner=".separator">
|
||||||
<input type="hidden" name="csrfToken" value="<?= $csrfToken ?>">
|
<input type="hidden" name="csrfToken" value="<?= $csrfToken ?>">
|
||||||
<div class="mob" onclick="document.forms['<?= $side ?>'].submit()">
|
<div class="mob" onclick="htmx.trigger(document.forms['<?= $side ?>'], 'submit', {})">
|
||||||
<h2><?= $mob["name"]; ?></h2>
|
<h2><?= $mob["name"]; ?></h2>
|
||||||
<img alt="<?= $mob["name"]; ?>" src="/images/mobs/<?= $mob["image"] ?? "_placeholder.png"; ?>">
|
<img alt="<?= $mob["name"]; ?>" src="/images/mobs/<?= $mob["image"] ?? "_placeholder.png"; ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
<h1>
|
<div class="choice">
|
||||||
Which do you like better?
|
<h1>
|
||||||
</h1>
|
Which do you like better?
|
||||||
<div class="selection">
|
</h1>
|
||||||
<?php
|
<div class="selection">
|
||||||
$mob = $left ?? [];
|
<?php
|
||||||
$side = "left";
|
$mob = $left ?? [];
|
||||||
include __DIR__ . "/mob.php";
|
$side = "left";
|
||||||
?>
|
include __DIR__ . "/mob.php";
|
||||||
<div class="separator">
|
?>
|
||||||
<div>
|
<div class="separator">
|
||||||
OR
|
<div class="or">
|
||||||
|
OR
|
||||||
|
</div>
|
||||||
|
<div class="spinner">
|
||||||
|
<img src="/images/gras.png" alt="spinner" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php
|
||||||
|
$mob = $right ?? [];
|
||||||
|
$side = "right";
|
||||||
|
include __DIR__ . "/mob.php";
|
||||||
|
?>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
|
||||||
$mob = $right ?? [];
|
|
||||||
$side = "right";
|
|
||||||
include __DIR__ . "/mob.php";
|
|
||||||
?>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue