This is the template project that's checked out and configured when you run the bando-up command from ljsthw-bandolier. This is where the code really lives.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
bandolier-template/client/components/Chat.svelte

217 lines
4.9 KiB

<script>
import { user } from "$/client/stores.js";
import { reconnect_socket } from '$/client/websocket.js';
import { onMount, afterUpdate } from 'svelte';
import { fade } from 'svelte/transition';
import Login from './Login.svelte';
import Modal from './Modal.svelte';
let socket;
let admin_top = {initials: '@',
admin: true,
size_at: 0,
text: 'Welcome to the chat. Introduce yourself and abstain from drama.'
}
const messages_height = 11;
let admin_messages = [admin_top];
let messages = [admin_top];
let login_dialog = false;
let message_input = "";
$: if(admin_top && !admin_top.display_at && messages.length - admin_top.size_at > messages_height) {
// mark the new one for display
admin_top.display = true;
// kick off a timer to hide it after 10 seconds on top
admin_top.display_at = new Date();
}
const user_authenticated = () => {
login_dialog = false;
$user.authenticated = true; // this seems to not get updated sometimes
socket = reconnect_socket();
}
afterUpdate(() => {
let msg_scroll = document.getElementById('messages');
msg_scroll.scrollTop = msg_scroll.scrollHeight;
});
const config_socket = () => {
let sock = reconnect_socket();
sock.on("/chat/message", (data) => {
data.size_at = messages.length;
messages.push(data);
messages = messages;
if(data.admin) {
admin_messages.push(data);
admin_top = admin_messages[admin_messages.length - 1];
}
});
return sock;
}
onMount(() => {
if($user.authenticated) {
// the socket connection sometimes isn't actually
// authenticated to just reconnect if the users is auth
socket = config_socket();
}
window.setInterval(() => {
if(admin_top && admin_top.display) {
// see if this is old and kick it off
const live_time = Date.now() - admin_top.display_at;
if(live_time > 10000) {
admin_top.display = false;
}
}
}, 1000);
});
const focus_input = () => {
document.getElementById('message-input').focus();
}
const send_message = () => {
if(message_input.trim() !== "") {
let msg = {user_id: $user.id, text: message_input};
socket.emit("/chat/message", msg);
message_input = "";
}
focus_input();
}
</script>
<style>
chat {
display: flex;
flex-direction: column;
font-size: 0.8em;
position: relative;
height: 100%;
}
chat messages {
display: flex;
flex-direction: column;
overflow-y: hidden;
overflow-x: hidden;
height: 100%;
margin-bottom: 0px;
}
chat messages:hover {
overflow-y: auto;
}
chat messages message from {
margin-right: 0.9rem;
background-color: #555;
color: #fff;
padding: 0.2rem;
border-radius: 50%;
font-size: 0.5em;
border: 1px solid var(--color-accent);
}
chat messages message {
padding: 0.3rem;
}
chat message.persistent {
padding: 0.3rem;
box-shadow: var(--box-shadow) var(--color-shadow);
position: absolute;
top: 0;
left: 0;
right: 0;
margin: 2px;
}
chat message.admin {
background-color: var(--color-bg-tertiary);
padding-top: 0.5rem;
padding-bottom: 0.5rem;
font-size: 0.9rem;
}
chat form {
display: flex;
border: unset;
padding: unset;
justify-content: space-evenly;
max-width: unset;
min-width: unset;
flex-direction: column;
}
chat-input form {
box-shadow: unset;
}
chat-input form input {
border: 1px solid var(--color-accent);
margin-bottom: unset;
width: 100%;
max-width: unset;
padding: 4px !important;
background: var(--color-bg-secondary);
box-sizing: border-box;
color: var(--color-text);
}
input#login-to-chat {
border: 1px solid #222;
margin-bottom: unset;
border-radius: 0px 0px 0px 0px;
}
input#login-to-chat:hover {
cursor: progress;
}
</style>
<chat data-testid="chat-panel">
{#if admin_top && admin_top.display }
<message in:fade out:fade class="admin persistent">
<from>{admin_top.initials}</from><span>{admin_top.text}</span>
</message>
{/if}
<messages id="messages">
{#each messages as message, i}
<message in:fade class:admin={ message.admin }>
<from>{message.initials}</from><span>{message.text}</span>
</message>
{/each}
</messages>
{#if $user.authenticated}
<chat-input in:fade>
<form autocomplete="off" on:submit|preventDefault={ send_message }>
<input id="message-input" type="text" name="message" bind:value={message_input}>
</form>
</chat-input>
{:else}
<input type="button" on:click={ () => login_dialog = true } id="login-to-chat" value="Login to Chat">
{/if}
</chat>
{#if login_dialog}
<Modal on:close={ () => login_dialog = false }>
<Login on:authenticated={ user_authenticated }
on:canceled={ () => login_dialog = false }
/>
</Modal>
{/if}