/ concept-collection / trystero-messaging-demo
Sign in
concept-collection / trystero-messaging-demo
trystero-messaging-demo / src / components / Header.tsx
75 lines · 1.9 KBBlameHistoryRaw
1import {useEffect, useState} from 'react'
2import {shortId} from '../util'
4type Props = {
5 roomId: string
6 selfId: string
7 selfName: string
8 onChangeName: (name: string) => void
9 peerCount: number
10 relayCount: number
13export function Header({
14 roomId,
15 selfId,
16 selfName,
17 onChangeName,
18 peerCount,
19 relayCount
20}: Props) {
21 const [draft, setDraft] = useState(selfName)
23 // keep the input in sync if the committed name changes elsewhere
24 useEffect(() => setDraft(selfName), [selfName])
26 const commit = () => {
27 if (draft !== selfName) onChangeName(draft)
28 }
30 return (
31 <header className="header">
32 <div className="header-title">
33 <h1>
34 🤝 Trystero P2P Messaging
35 </h1>
36 <p className="subtitle">
37 Serverless WebRTC over Nostr — no backend, no accounts. Open this page
38 in another tab or on another device to see peers appear.
39 </p>
40 </div>
42 <div className="identity">
43 <label className="field">
44 <span className="field-label">Your name</span>
45 <input
46 className="name-input"
47 value={draft}
48 onChange={e => setDraft(e.target.value)}
49 onBlur={commit}
50 onKeyDown={e => {
51 if (e.key === 'Enter') {
52 e.currentTarget.blur()
53 }
54 }}
55 maxLength={32}
56 />
57 </label>
58 <div className="identity-meta">
59 <span title={selfId}>
60 id <code>{shortId(selfId)}</code>
61 </span>
62 <span>
63 room <code>{roomId}</code>
64 </span>
65 <span>
66 <b>{peerCount}</b> peer{peerCount === 1 ? '' : 's'} connected
67 </span>
68 <span className={relayCount > 0 ? 'dot ok' : 'dot'}>
69 {relayCount} nostr relay{relayCount === 1 ? '' : 's'}
70 </span>
71 </div>
72 </div>
73 </header>
74 )
↑↓ move↵openescclose