concept-collection / trystero-messaging-demo
trystero-messaging-demo / src / components / MessageLog.tsx
84 lines · 2.2 KBBlameHistoryRaw
1import {useEffect, useRef} from 'react'
2import type {LogEntry} from '../types'
3import {formatBytes} from '../util'
5type Props = {
6 log: LogEntry[]
7 onClear: () => void
8}
10const time = (t: number) =>
11 new Date(t).toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', second: '2-digit'})
13export function MessageLog({log, onClear}: Props) {
14 const bottomRef = useRef<HTMLDivElement>(null)
16 // autoscroll to the newest entry
17 useEffect(() => {
18 bottomRef.current?.scrollIntoView({behavior: 'smooth', block: 'end'})
19 }, [log.length])
21 return (
22 <div className="panel log-panel">
23 <h2 className="panel-title">
24 Message log
25 <button className="btn tiny" onClick={onClear} disabled={log.length === 0}>
26 clear
27 </button>
28 </h2>
30 <div className="log">
31 {log.length === 0 && (
32 <p className="empty">Messages and transfers will appear here.</p>
33 )}
34 {log.map(e => (
35 <LogRow key={e.key} e={e} />
36 ))}
37 <div ref={bottomRef} />
38 </div>
39 </div>
40 )
43function LogRow({e}: {e: LogEntry}) {
44 if (e.kind === 'system') {
45 return (
46 <div className="log-row system">
47 <span className="log-time">{time(e.time)}</span>
48 <span className="log-body">{e.text}</span>
49 </div>
50 )
51 }
53 const arrow = e.dir === 'out' ? '→' : '←'
54 const who =
55 e.dir === 'out' ? `to ${e.peerName}` : `from ${e.peerName}`
57 return (
58 <div className={`log-row ${e.dir}`}>
59 <span className="log-time">{time(e.time)}</span>
60 <span className="log-body">
61 <span className="log-who">
62 {arrow} {who}
63 </span>
64 {e.kind === 'text' ? (
65 <span className="log-text">{e.text}</span>
66 ) : (
67 <span className="log-binary">
68 📦 <b>{e.fileName}</b> · {formatBytes(e.size ?? 0)}
69 {e.blobUrl && (
70 <a className="dl" href={e.blobUrl} download={e.fileName}>
71 download
72 </a>
73 )}
74 {e.sha256 && (
75 <code className="sha" title={`SHA-256: ${e.sha256}`}>
76 sha256 {e.sha256.slice(0, 12)}…
77 </code>
78 )}
79 </span>
80 )}
81 </span>
82 </div>
83 )