chore: remove orphaned legacy files and move QR scanner to elements/

- Trashed 10 unreferenced files: core .legacy types, bak files, element_modal_v1, element_websocket_v2, AE_MetadataFooter_not_ref, element_qr_scanner_v2
- Removed empty placeholder dirs: ae_db/, hooks/
- Moved element_qr_scanner_v3.svelte from lib root into elements/
- Updated 2 import paths for QR scanner (badges + leads)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-20 09:45:57 -04:00
parent 60461de9d9
commit 0d960435f8
11 changed files with 3 additions and 2622 deletions

View File

@@ -1,205 +0,0 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
interface Props {
open?: boolean;
title?: string;
autoclose?: boolean;
size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl';
placement?: 'top-center' | 'center' | 'bottom-center';
class_li?: string; // Additional classes for the dialog
header?: import('svelte').Snippet;
children?: import('svelte').Snippet;
footer?: import('svelte').Snippet;
}
let {
open = $bindable(false),
title = '',
autoclose = true,
size = 'md',
placement = 'center',
class_li = '',
header,
children,
footer
}: Props = $props();
let dialog_element: HTMLDialogElement;
// Open/close dialog reactively
$effect(() => {
if (dialog_element) {
if (open) {
dialog_element.showModal();
} else {
dialog_element.close();
}
}
});
onMount(() => {
// Handle backdrop click to close (if autoclose is true)
dialog_element.addEventListener('click', (event) => {
if (autoclose && event.target === dialog_element) {
open = false;
}
});
// Handle Escape key to close
const handle_keydown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && open) {
event.preventDefault(); // Prevent default browser escape behavior (e.g., page back)
open = false;
}
};
window.addEventListener('keydown', handle_keydown);
onDestroy(() => {
window.removeEventListener('keydown', handle_keydown);
});
});
// Determine max-width based on size prop
let max_width_class = $derived(
size === 'sm'
? 'max-w-sm'
: size === 'md'
? 'max-w-md'
: size === 'lg'
? 'max-w-lg'
: size === 'xl'
? 'max-w-xl'
: size === '2xl'
? 'max-w-2xl'
: size === '3xl'
? 'max-w-3xl'
: size === '4xl'
? 'max-w-4xl'
: size === '5xl'
? 'max-w-5xl'
: size === '6xl'
? 'max-w-6xl'
: size === '7xl'
? 'max-w-7xl'
: 'max-w-md'
);
// Determine placement classes
let placement_class = $derived(
placement === 'top-center'
? 'justify-center items-start pt-[5vh]'
: placement === 'center'
? 'justify-center items-center'
: placement === 'bottom-center'
? 'justify-center items-end pb-[5vh]'
: 'justify-center items-center' // Default to center
);
</script>
<dialog
bind:this={dialog_element}
class="
p-0 bg-transparent overflow-visible
backdrop:bg-black/50 backdrop:backdrop-blur-sm
"
onclose={() => (open = false)}
>
<div
class="
bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg shadow-xl
flex flex-col
mx-auto
{max_width_class}
w-full
{class_li}
"
>
<!-- Modal Header -->
{#if title || header}
<header
class="flex items-center justify-between border-b border-gray-200 p-4 dark:border-gray-700"
>
{#if header}
{@render header()}
{:else}
<h3 class="text-xl font-semibold">{title}</h3>
{/if}
<button
onclick={() => (open = false)}
class="rounded-full p-1 hover:bg-gray-200 dark:hover:bg-gray-700"
title="Close modal"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</header>
{/if}
<!-- Modal Body -->
<main class="max-h-[70vh] overflow-y-auto p-4">
{#if children}
{@render children()}
{/if}
</main>
<!-- Modal Footer -->
{#if footer}
<footer class="border-t border-gray-200 p-4 dark:border-gray-700">
{@render footer()}
</footer>
{/if}
</div>
</dialog>
<style lang="postcss">
dialog {
display: flex; /* Override default to allow flexbox positioning */
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
}
dialog[open] {
opacity: 0;
animation: fade-in 0.15s forwards ease-out;
}
dialog:not([open]) {
opacity: 1;
animation: fade-out 0.15s forwards ease-out;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
pointer-events: none; /* Disable interaction while fading out */
}
}
</style>

View File

@@ -0,0 +1,143 @@
<script lang="ts">
/**
* src/lib/elements/element_qr_scanner_v3.svelte
* QR Scanner v3 — Svelte 5 runes, auto-starts, no manual permission step.
*
* html5-qrcode's .start() handles camera permission internally.
* A unique viewfinder ID is generated per instance so multiple scanners
* can coexist on the same page without collision.
*
* Props:
* start_qr_scanner (bindable) — true = scan, false = stop
* on_qr_scan_result — callback fired with { detail: { result, entry_method } }
* qr_fps — scan frames per second (default 10)
* qr_facing_mode — 'environment' (rear) or 'user' (front)
*/
import { onDestroy, untrack } from 'svelte';
import { Html5Qrcode, Html5QrcodeSupportedFormats } from 'html5-qrcode';
interface Props {
start_qr_scanner?: boolean;
on_qr_scan_result?: (event: { detail: { result: string; entry_method: string } }) => void;
qr_fps?: number;
qr_facing_mode?: string;
}
let {
start_qr_scanner = $bindable(true),
on_qr_scan_result,
qr_fps = 10,
qr_facing_mode = 'environment'
}: Props = $props();
// Unique DOM ID per instance — prevents conflicts when multiple scanners mount
const viewfinder_id = `qr_vf_${Math.random().toString(36).substring(2, 9)}`;
let scanner: Html5Qrcode | null = null;
let status = $state<'idle' | 'starting' | 'scanning' | 'error'>('idle');
let error_msg = $state('');
// React to start_qr_scanner prop changes from the parent
$effect(() => {
const should_scan = start_qr_scanner;
untrack(() => {
if (should_scan && (status === 'idle' || status === 'error')) {
start_scanning();
} else if (!should_scan && status === 'scanning') {
stop_scanning();
}
});
});
onDestroy(() => {
stop_scanning();
});
async function start_scanning() {
if (status === 'starting' || status === 'scanning') return;
status = 'starting';
error_msg = '';
try {
scanner = new Html5Qrcode(viewfinder_id, {
formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE],
verbose: false
});
await scanner.start(
{ facingMode: qr_facing_mode },
{
fps: qr_fps,
// Use a percentage of the viewfinder so it scales on any screen size
qrbox: (w: number, h: number) => {
const side = Math.floor(Math.min(w, h) * 0.82);
return { width: side, height: side };
}
},
on_scan_success,
on_scan_error
);
status = 'scanning';
} catch (e: any) {
status = 'error';
if (e?.name === 'NotAllowedError') {
error_msg = 'Camera access denied. Please allow camera in your browser settings and try again.';
} else {
error_msg = 'Could not start camera. Please try again.';
}
console.warn('[QR v3] Scanner start failed:', e);
}
}
async function stop_scanning() {
if (!scanner) return;
const s = scanner;
scanner = null;
try {
await s.stop();
await s.clear();
} catch {
// Ignore cleanup errors — component may be unmounting
}
status = 'idle';
}
function on_scan_success(decoded_text: string) {
// Stop scanning before notifying parent so the camera shuts down cleanly
stop_scanning().then(() => {
start_qr_scanner = false;
});
if (on_qr_scan_result) {
on_qr_scan_result({ detail: { result: decoded_text, entry_method: 'QR' } });
}
}
function on_scan_error(_msg: string) {
// Called on every frame that doesn't contain a QR code — expected, not an error
}
</script>
<!-- Viewfinder fills whatever container the parent provides -->
<div class="qr-scanner-v3 w-full h-full flex flex-col items-center justify-center">
<div id={viewfinder_id} class="w-full h-full"></div>
{#if status === 'starting'}
<div class="absolute inset-0 flex items-center justify-center bg-surface-900/40 rounded-xl">
<p class="text-sm font-semibold opacity-70 animate-pulse">Starting camera...</p>
</div>
{:else if status === 'error'}
<div class="absolute inset-0 flex flex-col items-center justify-center gap-4 bg-surface-900/80 rounded-xl p-6 text-center">
<p class="text-sm text-error-400 font-semibold leading-snug">{error_msg}</p>
<button
type="button"
class="btn btn-sm preset-filled-primary"
onclick={start_scanning}
>
Try Again
</button>
</div>
{/if}
</div>

View File

@@ -1,597 +0,0 @@
<script lang="ts">
interface Props {
log_lvl?: number;
ws_connect?: boolean; // If true then we should be trying to connect to the WS server.
ws_connect_status?: null | string;
ws_server?: string;
ws_retry_delay?: number;
ws_retry_count?: number;
base_url?: any;
group_id?: string;
client_id?: any;
cmd?: null | string;
msg?: null | string;
type?: null | string; // msg, cmd, json, hello, bye
trigger_send?: any;
trigger_connect?: boolean;
trigger_disconnect?: boolean;
classes?: string;
hide__ws_element?: boolean;
hide__ws_form?: boolean;
hide__ws_messages?: boolean;
hide__ws_commands?: boolean;
ws_conn_status?: any;
ws_recv_status?: any;
ws_sent_status?: any;
}
let {
log_lvl = 0,
ws_connect = $bindable(false),
ws_connect_status = $bindable(null),
ws_server = 'dev-api.oneskyit.com',
ws_retry_delay = 3500,
ws_retry_count = 0,
base_url = `wss://${ws_server}/ws`,
group_id = $bindable('ae-grp-99'),
client_id = $bindable(Date.now()),
cmd = $bindable(null),
msg = $bindable(null),
type = null,
trigger_send = $bindable(null),
trigger_connect = $bindable(false),
trigger_disconnect = $bindable(false),
classes = 'container p-1 bg-pink-100 text-xs mx-auto pb-16 mb-20 sm:mb-12 md:mb-8',
hide__ws_element = $bindable(false),
hide__ws_form = $bindable(true),
hide__ws_messages = $bindable(false),
hide__ws_commands = $bindable(false),
ws_conn_status = $bindable(null),
ws_recv_status = $bindable(null),
ws_sent_status = $bindable(null)
}: Props = $props();
// import { run, prevent_default } from 'svelte/legacy';
// import { createEventDispatcher, onMount } from 'svelte';
// *** Set initial variables
// const dispatch = createEventDispatcher();
// JSON formatted data
let ws_data: {
client_id: string | null;
target: string;
type: string;
msg: string | null;
cmd: string | null;
} = $state({
client_id: null, // The device or browser ID if available.
// 'src': null, // Sending client
// 'account_id': null, // Essentially the person ID or user ID if available.
// 'dest': null, // Destination client
target: 'echo', // echo, dm (direct), grp (group), all (broadcast)
type: 'cmd', // msg, cmd, json, hello, bye
// 'grp': null, // Destination group
msg: null, // Message string
cmd: null // Command string
// 'data': null,
// 'b64': null,
});
let ws_received_list_cmd: any[] = $state([]);
let ws_received_list_other: any[] = $state([]);
let ws_received_list_msg: string[] = [];
// onMount(async () => {
// console.log('** Component Mounted: ** Element Websocket v2');
// });
// *** Functions and Logic
function ws_connect_group_id({ group_id, client_id }: { group_id: string, client_id: any }) {
if (!group_id) {
group_id = 'ae-grp-99';
console.log(
`WS: No group_id specified! Setting to default: ${group_id}`
);
return false;
}
if (!client_id) {
client_id = Date.now();
console.log(
`WS: No client_id specified! Setting to current timestamp: ${client_id}`
);
// return false;
}
console.log(
`WS Connect URL: ${base_url}/group/${group_id}/client/${client_id}`
);
let ws_connection = new WebSocket(
`${base_url}/group/${group_id}/client/${client_id}`
);
ws_connection.onopen = function () {
console.log('WS: connected');
ws_connect_status = 'connected';
// dispatch('ws_conn', {
// 'status': 'connected'
// });
ws_conn_status = 'connected';
ws_retry_count = 0;
// ws_connection.send(JSON.stringify({
// client_id: client_id,
// target: 'echo',
// type: 'hello',
// group_id: group_id,
// msg: 'You are connected!'
// }));
ws_connection.send(
JSON.stringify({
client_id: client_id,
target: 'all',
type: 'hello',
group_id: group_id,
msg: `Client ${client_id.toString().slice(-5)} connected!`
})
);
};
ws_connection.onmessage = function (event) {
if (log_lvl) {
console.log('WS: message received', event);
}
let ws_recv_data = JSON.parse(event.data);
if (log_lvl) {
console.log('WS: Received data:', ws_recv_data);
}
if (client_id == ws_recv_data.client_id) {
if (log_lvl) {
console.log(
'WS: Message received was sent by self and is an echo that can be ignored.'
);
}
return false;
}
if (ws_recv_data.type == 'cmd') {
console.log(`WS: Type CMD: ${ws_recv_data.cmd}`);
ws_received_list_cmd.unshift(ws_recv_data); // Add to the beginning of the list
// ws_received_list_cmd.push(ws_recv_data); // Add to the end of the list
ws_received_list_cmd = ws_received_list_cmd; // trigger Svelte update -2024-10-04
} else {
console.log('WS: Type other');
ws_received_list_other.unshift(ws_recv_data); // Add to the beginning of the list
// ws_received_list_other.push(ws_recv_data); // Add to the end of the list
ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04
}
// dispatch('ws_recv', {
// // 'client_id': ws_data.client_id, // The device or browser ID if available.
// 'src': ws_recv_data.client_id, // The device or browser ID if available.
// // 'account_id': ws_recv_data.account_id, // Essentially the person ID or user ID if available.
// 'dest': group_id, // Destination client
// 'target': ws_recv_data.target, // echo, dm (direct), grp (group), all (broadcast)
// 'type': ws_recv_data.type, // Message type (msg, cmd, json, hello, bye)
// // 'grp': ws_recv_data.grp, // Destination group
// 'msg': ws_recv_data.msg, // Message string
// 'cmd': ws_recv_data.cmd, // Command string
// });
ws_recv_status = {
// 'client_id': ws_data.client_id, // The device or browser ID if available.
src: ws_recv_data.client_id, // The device or browser ID if available.
// 'account_id': ws_recv_data.account_id, // Essentially the person ID or user ID if available.
dest: group_id, // Destination client
target: ws_recv_data.target, // echo, dm (direct), grp (group), all (broadcast)
type: ws_recv_data.type, // Message type (msg, cmd, json, hello, bye)
// 'grp': ws_recv_data.grp, // Destination group
msg: ws_recv_data.msg, // Message string
cmd: ws_recv_data.cmd // Command string
};
};
ws_connection.onclose = function (event) {
console.log('WS: connection closed');
ws_connection.send(
JSON.stringify({
client_id: client_id,
target: 'all',
type: 'hello',
group_id: group_id,
msg: `Client ${client_id} is disconnecting!`
})
);
ws_connect_status = 'disconnected';
let fake_ws_recv_data = {
client_id: client_id,
target: 'local',
type: 'bye',
group_id: group_id,
msg: `LOCAL Client ${client_id} has disconnected!`
};
ws_received_list_other.unshift(fake_ws_recv_data);
ws_received_list_other = ws_received_list_other; // trigger Svelte update -2024-10-04
// dispatch('ws_conn', {
// 'status': 'disconnected'
// });
ws_conn_status = 'disconnected';
if (ws_connect) {
if (ws_retry_count >= 10) {
ws_retry_delay = ws_retry_delay += 4999; // Set to a very long time
ws_retry_delay = Math.min(ws_retry_delay, 120000); // Max of 2 minutes
console.log(
`WS: Retry count exceeded. Increasing the delay. ws_retry_count=${ws_retry_count} ws_retry_delay=${ws_retry_delay}`
);
}
setTimeout(function () {
console.log('WS: Disconnected... Try again!');
ws_retry_count += 1;
ws_connect_group_id({
group_id: group_id,
client_id: client_id
});
console.log('WS: Again done?');
}, ws_retry_delay);
}
};
ws_connection.onerror = function (event) {
console.log('WS: connection error???');
ws_connection.send(
JSON.stringify({
client_id: client_id,
target: 'all',
type: 'hello',
group_id: group_id,
msg: `Client ${client_id} is having trouble?!`
})
);
};
// NOTE WARNING: Uncommenting this seems to break FastAPI somehow???
// NOTE: from FastAPI log: RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.
// ws_connection.onerror = function(err) {
// console.error('WS socket error: ', err.message, 'Closing socket');
// // ws_connection.close();
// };
return ws_connection;
}
// Start the WS function
let ws_group: any = $state(null);
function handle_send_ws_data() {
console.log(ws_data);
if (!ws_data) {
return false;
}
if (!ws_group) {
console.log('WS: No connection!');
return false;
}
let ws_data_json_str = JSON.stringify(ws_data);
let resp = ws_group.send(ws_data_json_str);
console.log(`WS: Send data response:`, resp);
// dispatch('ws_sent', {
// // 'client_id': ws_data.client_id, // The device or browser ID if available.
// 'src': ws_data.client_id, // The device or browser ID if available.
// // 'account_id': ws_data.account_id, // Essentially the person ID or user ID if available.
// 'dest': group_id, // Destination client
// 'group_id': group_id,
// 'target': ws_data.target, // echo, dm (direct), grp (group), all (broadcast)
// 'type': ws_data.type, // Message type (msg, cmd, json, hello, bye)
// // 'grp': ws_data.grp, // Destination group
// 'msg': ws_data.msg, // Message string
// 'cmd': ws_data.cmd, // Command string
// });
ws_sent_status = {
// 'client_id': ws_data.client_id, // The device or browser ID if available.
src: ws_data.client_id, // The device or browser ID if available.
// 'account_id': ws_data.account_id, // Essentially the person ID or user ID if available.
dest: group_id, // Destination client
group_id: group_id,
target: ws_data.target, // echo, dm (direct), grp (group), all (broadcast)
type: ws_data.type, // Message type (msg, cmd, json, hello, bye)
// 'grp': ws_data.grp, // Destination group
msg: ws_data.msg, // Message string
cmd: ws_data.cmd // Command string
};
cmd = '';
msg = '';
}
$effect(() => {
if (ws_connect && group_id) {
console.log('HERE!!!!!');
ws_group = ws_connect_group_id({
group_id: group_id,
client_id: client_id
});
// } else if (!ws_connect) {
// console.log('HERE!!!!!');
// log_lvl = 1;
// if (log_lvl) {
// console.log(`WS: WS not set to connect. Need to close WS Group connection.`);
// }
// ws_group?.close();
// ws_connect_status = 'disconnected';
} else {
console.log('HERE!!!!!');
log_lvl = 1;
if (log_lvl) {
console.log(
`WS: Not connecting. ws_connect=${ws_connect} group_id=${group_id}`
);
}
ws_group?.close();
ws_connect_status = 'disconnected';
}
});
$effect(() => {
if (trigger_send && cmd) {
trigger_send = null;
console.log('WS: Send triggered!');
console.log(cmd);
ws_data.target = 'group';
ws_data.type = 'cmd';
ws_data.cmd = cmd;
handle_send_ws_data();
cmd = '';
}
});
$effect(() => {
if (trigger_connect) {
trigger_connect = false;
if (!ws_connect) {
ws_connect = true;
}
console.log('WS: Connect triggered!');
}
});
$effect(() => {
if (trigger_disconnect) {
console.log('WS: Disconnect triggered!');
trigger_disconnect = false;
if (ws_connect) {
ws_connect = false;
}
if (ws_group) {
ws_group.close();
ws_group = null;
ws_connect_status = 'disconnected';
}
}
});
function prevent_default<T extends Event>(fn: (event: T) => void) {
return function (event: T) {
event.preventDefault();
fn(event);
};
}
</script>
<section
class:hidden={!ws_connect || hide__ws_element}
class="ae_element__websocket container p-1 bg-pink-100 text-xs mx-auto pb-16 mt-32 mb-32 relative"
>
<span class="absolute top-0 right-0 flex flex-col gap-1">
<button
type="button"
onclick={() => {
hide__ws_form = !hide__ws_form;
}}
class="btn btn-sm text-xs hover:preset-filled-tertiary-500"
class:preset-tonal-tertiary={hide__ws_form}
class:preset-filled-tertiary-500={!hide__ws_form}
>
{#if hide__ws_form}
Show Form
{:else}
Hide Form?
{/if}
</button>
<button
type="button"
onclick={() => {
hide__ws_messages = !hide__ws_messages;
}}
class="btn btn-sm text-xs hover:preset-filled-tertiary-500"
class:preset-tonal-tertiary={hide__ws_messages}
class:preset-filled-tertiary-500={!hide__ws_messages}
>
{#if hide__ws_messages}
Show Messages
{:else}
Hide Messages?
{/if}
</button>
<button
type="button"
onclick={() => {
hide__ws_commands = !hide__ws_commands;
}}
class="btn btn-sm text-xs hover:preset-filled-tertiary-500"
class:preset-tonal-tertiary={hide__ws_commands}
class:preset-filled-tertiary-500={!hide__ws_commands}
>
{#if hide__ws_commands}
Show Commands
{:else}
Hide Commands?
{/if}
</button>
</span>
<header>
<h1 class="h6 text-center">Websocket Messages & Commands</h1>
</header>
<!-- <form on:submit|prevent_default={handle_send_message}>
<select bind:value={type}>
<option value="">None</option>
<option value="echo">Echo</option>
<option value="dm">Direct Message</option>
<option value="group">Group Message</option>
<option value="all">Broadcast to All</option>
<option value="cmd">Command</option>
</select>
<select bind:value={group_id}>
<option value="">None</option>
<option value="test_grp_123">123</option>
<option value="test_grp_999">999</option>
<option value="test_grp_poster">A Poster Group</option>
</select>
<input type="text" bind:value={message_text} placeholder="Your message"/>
<button>Send</button>
</form> -->
{#if !hide__ws_form}
<form onsubmit={prevent_default(handle_send_ws_data)}>
<select bind:value={ws_data.type} class="input text-sm w-24">
<option value="">None</option>
<option value="echo">Echo</option>
<option value="dm">Direct Message</option>
<option value="group">Group Message</option>
<option value="all">Broadcast to All</option>
<option value="cmd">Command</option>
</select>
<input
type="text"
bind:value={group_id}
placeholder="Group ID"
class="input text-sm w-36"
/>
<!-- <select bind:value={group_id}>
<option value="">None</option>
<option value="test_grp_123">123</option>
<option value="test_grp_999">999</option>
<option value="test_grp_poster">A Poster Group</option>
</select> -->
<!-- <input type="text" bind:value={dm_client_id} placeholder="Direct message client ID"/> -->
<input
type="text"
bind:value={ws_data.cmd}
placeholder="Your command"
class="input text-sm w-36"
/>
<input
type="text"
bind:value={ws_data.msg}
placeholder="Your message"
class="input text-xs w-96"
/>
<button type="submit" class="btn btn-sm preset-tonal-warning"
>Send Group</button
>
</form>
{/if}
<!-- <pre>
ae_load:event_session=jEG9APQRUs8 (Poster Session #3: Work Never Ends - Pythagoras)
ae_open:event_file=CHqU5sW7xbc (jpg)
ae_open:event_file=Kljq0uiTlXt (video)
</pre> -->
<!-- <hr> -->
<section class:hidden={hide__ws_messages}>
<h2 class="text-center underline">
Messages [grp, client, target, type]
</h2>
<ol class="list-decimal list-outside max-h-24 overflow-y-auto messages">
{#each ws_received_list_other as msg_entry, index (index)}
<li class="ml-4">
<div class="flex flex-row justify-between gap-1 w-full">
<span>
[{msg_entry.group_id || 'No Group ID'}]
{msg_entry.client_id.toString().slice(-5) ||
'No Client ID'}
{msg_entry.target || 'No Target'}
|
<!-- &ndash; -->
{msg_entry.type || 'No Type'}:
</span>
<span class="justify-self-end">
"{msg_entry.msg}"
</span>
<!-- <br>{JSON.stringify(msg_entry)} -->
</div>
</li>
{/each}
</ol>
</section>
<!-- End Messages -->
<hr />
<section class:hidden={hide__ws_commands}>
<h2 class="text-center underline">Commands</h2>
<ol class="list-decimal list-outside max-h-24 overflow-y-auto commands">
{#each ws_received_list_cmd as cmd_entry, index (index)}
<li class="ml-4">
<div class="flex flex-row justify-between gap-1 w-full">
<span>
[{cmd_entry.group_id || 'No Group ID'}]
{cmd_entry.client_id.toString().slice(-5) ||
'No Client ID'}
{cmd_entry.target || 'No Target'}
|
<!-- &mdash; -->
{cmd_entry.type || 'No Type'}:
</span>
<span class="justify-self-end">
"{cmd_entry.cmd}"
</span>
</div>
</li>
{/each}
</ol>
</section>
<!-- End Commands -->
</section>
<style>
/* .websocket_element {
background-color: white;
border-top: dashed medium gray;
color: gray;
font-size: .7em;
}
.websocket_element header {
font-size: .7em;
}
.websocket_element h2 {
font-size: .9em;
} */
</style>