Made the babblebox a live, reactive component

This commit is contained in:
Sky Johnson 2024-12-18 10:51:29 -06:00
parent 1b9106fadb
commit faefbb37d4
7 changed files with 92 additions and 68 deletions

View File

@ -2,6 +2,10 @@
--font-size: 12px;
}
* {
box-sizing: border-box;
}
html {
font-size: var(--font-size);
font-family: sans-serif;
@ -200,3 +204,26 @@ div.stat-bar > div {
position: absolute;
bottom: 0;
}
#babblebox > .messages {
max-height: 200px;
overflow-y: auto;
}
#babblebox > .messages .message {
padding: 0.25rem;
background-color: #eee;
&:nth-child(even) {
background-color: white;
}
}
#babblebox > form {
margin-top: 0 !important;
& > input[type="text"] {
width: 100%;
margin-bottom: 0.5rem;
}
}

View File

@ -4,6 +4,12 @@
require_once '../src/bootstrap.php';
// Do an early return with babblebox data if that's what's being requested
if ($uri[0] === 'babblebox' && (isset($uri[1]) && $uri[1] === 'messages')) {
echo babblebox_messages();
exit;
}
$r = new Router;
$r->get('/', function() {
@ -39,14 +45,14 @@ $r->get('/character', 'show_character_info');
$r->get('/character/:id', 'show_character_info');
$r->get('/showmap', 'showmap');
$r->form('/babblebox', 'babblebox');
$r->get('/babblebox/messages', 'babblebox_messages');
// [code, handler, params, middleware]
$l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
if (is_int($l)) exit("Error: $l");
if (!empty($l['middleware'])) foreach ($l['middleware'] as $middleware) $middleware();
$content = $l['handler'](...$l['params'] ?? []);
if (is_htmx()) {
if (is_htmx() && $uri[0] !== 'babblebox') {
$content .= Render\debug_db_info();
if ($GLOBALS['state']['user-state-changed'] ?? false) {
$content .= Render\right_nav();
@ -113,22 +119,36 @@ function showmap()
}
/**
* Either render the latest 40 chats to the babblebox, or add a chat to it and redirect. This is used
* within an iframe.
* ...
*/
function babblebox()
{
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$safecontent = make_safe($_POST["babble"]);
if (!empty($safecontent)) {
$content = trim($_POST["babble"]);
if (!empty($content)) {
db()->query('INSERT INTO babble (posttime, author, babble) VALUES (CURRENT_TIMESTAMP, ?, ?);',
[user()->username, $safecontent]);
[user()->username, $content]);
}
redirect('/babblebox');
return babblebox_messages();
}
}
$query = db()->query('SELECT * FROM babble ORDER BY id DESC LIMIT 40;');
echo render('babblebox', ['messages' => $query]);
/**
* Is the handler for the HTMX get request for messages.
*/
function babblebox_messages(): string
{
if (user() === false) return '';
$query = db()->query('SELECT * FROM babble ORDER BY id ASC LIMIT 40;');
$has_chats = false;
$messages = '';
while ($row = $query->fetchArray(SQLITE3_ASSOC)) {
$has_chats = true;
$messages .= '<div class="message">[<b>' . $row['author'] . '</b>] ' . make_safe($row['babble']) . '</div>';
}
if (!$has_chats) $messages = 'There are no messages. :(';
return $messages;
}
/**

View File

@ -27,7 +27,7 @@ if (!file_exists('../.installed') && $uri[0] !== 'install') {
redirect('/install');
} elseif (file_exists(('../.installed')) && $uri[0] === 'install') {
redirect('/');
} elseif (file_exists(('../.installed')) && $uri[0] !== 'install') {
} else {
$controlrow = get_control_row();
if (!$controlrow["gameopen"]) {

View File

@ -38,3 +38,8 @@ function right_nav(): string
if (is_htmx()) $template = '<section id="right" hx-swap-oob="true">'.$template."</section>";
return $template;
}
function babblebox(): string
{
return render('babblebox', ['messages' => babblebox_messages()]);
}

View File

@ -1,58 +1,29 @@
<html lang="en">
<head>
<title>Babblebox</title>
<style type="text/css">
body {
background-image: url('/img/background.jpg');
color: black;
font: 11px verdana;
margin: 0px;
padding: 0px;
}
<div id="babblebox">
<div class="messages" hx-get="/babblebox/messages" hx-trigger="every 5s">
<?= $messages ?>
</div>
div {
padding: 2px;
border: solid 1px black;
margin: 2px;
text-align: left;
}
a {
color: #663300;
text-decoration: none;
font-weight: bold;
}
a:hover {
color: #330000;
}
div.message {
background-color: white;
}
div.message:nth-child(even) {
background-color: #eeeeee;
}
</style>
</head>
<body onload="window.scrollTo(0, 99999)">
<?php
$has_chats = false;
while ($row = $messages->fetchArray(SQLITE3_ASSOC)):
$has_chats = true;
?>
<div class="message">[<b><?= $row['author'] ?></b>] <?= $row['babble'] ?></div>
<?php
endwhile;
if (!$has_chats) echo 'There are no messages. :(';
?>
<form action="/babblebox" method="post" style="margin-top: 1rem;">
<input type="text" name="babble" maxlength="255" style="width: 100%;"><br>
<form hx-post="/babblebox" hx-target="#babblebox > .messages" style="margin-top: 1rem;">
<input type="text" name="babble" maxlength="255"><br>
<input type="submit" name="submit" value="Babble">
<input type="reset" name="reset" value="Clear">
</form>
</body>
</html>
<script>
const chatBox = document.querySelector('#babblebox > .messages')
let isUserAtBottom = true
if (chatBox !== null) {
chatBox.scrollTop = chatBox.scrollHeight;
const isAtBottom = () => chatBox.scrollHeight - chatBox.scrollTop === chatBox.clientHeight
const scrollChatToBottom = () => {
if (isUserAtBottom) chatBox.scrollTop = chatBox.scrollHeight;
}
const observer = new MutationObserver(scrollChatToBottom)
observer.observe(chatBox, { childList: true, subtree: true })
chatBox.addEventListener('scroll', () => isUserAtBottom = isAtBottom())
}
</script>
</div>

View File

@ -55,12 +55,12 @@
<script>
document.addEventListener("updateTitle", (event) => {
const title = event.detail?.title;
const title = event.detail?.title
if (title) {
console.log('New title:', title);
document.title = title;
}
});
})
</script>
</body>
</html>

View File

@ -18,6 +18,7 @@
</div>
<div class="babblebox">
<?= $town['babblebox'] ?>
<div class="title">Babblebox</div>
<?= Render\babblebox() ?>
</div>
</div>