React + TypeScript UI on port 5274. Connects to local daemon via WebSocket IPC (DaemonAdapter). Full chat layout with sidebar, message pane, and peer list. Mirrors the TUI feature set. - src/types.ts — IPC types mirroring proto.go - src/adapter/daemon — WebSocket IPC adapter with auto-reconnect - src/store/index.ts — Zustand store; handles all daemon events - src/pages/ — Onboarding (connect + join) and Chat - src/components/ — Sidebar, MessagePane, PeerList Dev: cd web && npm run dev (port 5274) Build: cd web && npm run build Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
import { useWaste } from '../store'
|
|
|
|
export function PeerList() {
|
|
const { connectedPeers, activeNetworkId, setActiveRoom, send } = useWaste()
|
|
|
|
function openDM(peerId: string) {
|
|
const room = `dm:${peerId}`
|
|
setActiveRoom(room)
|
|
}
|
|
|
|
function requestFiles(peerId: string) {
|
|
send({ type: 'get_file_list', network_id: activeNetworkId ?? undefined, peer_id: peerId })
|
|
}
|
|
|
|
return (
|
|
<aside className="peer-list">
|
|
<span className="sidebar-label">Peers ({connectedPeers.length})</span>
|
|
{connectedPeers.map(p => (
|
|
<div key={p.id} className="peer-entry">
|
|
<div className="peer-entry-info">
|
|
<span className="alias">{p.alias}</span>
|
|
<span className="peer-id">{p.id.slice(0, 8)}…</span>
|
|
</div>
|
|
<div className="peer-entry-actions">
|
|
<button onClick={() => openDM(p.id)} title="Direct message">DM</button>
|
|
<button onClick={() => requestFiles(p.id)} title="Browse files">Files</button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
{connectedPeers.length === 0 && (
|
|
<p className="empty">No peers connected yet</p>
|
|
)}
|
|
</aside>
|
|
)
|
|
}
|