feat: standalone web UI (React + Vite)

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>
This commit is contained in:
Fredrik Johansson
2026-06-22 21:57:32 +02:00
parent 77830a3b3f
commit ff14e955ea
27 changed files with 3782 additions and 0 deletions

104
web/src/types.ts Normal file
View File

@@ -0,0 +1,104 @@
// Types mirroring internal/proto — keep in sync with proto.go
export type PeerID = string // 64-char lowercase hex
export interface PeerInfo {
id: PeerID
alias: string
public_key: string
created_at: string
}
export interface NetworkInfo {
network_id: string
network_name: string
local_peer?: PeerInfo
share_dir?: string
download_dir?: string
}
export interface ChatMessage {
mid?: string
from: PeerID
to?: PeerID
room: string
text: string
ts: number // Unix ms
}
export interface FileEntry {
name: string
size_bytes: number
}
export interface FileOffer {
xid: string
name: string
size: number
sha256: string
}
// ── IPC message types ─────────────────────────────────────────────────────────
export type IpcMsgType =
// commands
| 'send_message'
| 'join_network'
| 'leave_network'
| 'get_state'
| 'send_file'
| 'set_share_dir'
| 'generate_invite'
| 'get_file_list'
| 'export_identity'
| 'import_identity'
// events
| 'state_snapshot'
| 'message_received'
| 'peer_connected'
| 'peer_disconnected'
| 'session_ready'
| 'network_joined'
| 'network_left'
| 'file_list'
| 'file_progress'
| 'file_complete'
| 'incoming_file'
| 'invite_generated'
| 'identity_exported'
| 'identity_imported'
| 'error'
export interface IpcMessage {
type: IpcMsgType
// routing
network_id?: string
// send_message
room?: string
to?: PeerID
body?: string
// join_network
network_name?: string
share_dir?: string
// send_file / set_share_dir
path?: string
peer_id?: PeerID
// identity
passphrase?: string
backup?: string
// events
peer?: PeerInfo
nick?: string
message?: ChatMessage
offer?: FileOffer
transfer_id?: string
bytes_received?: number
total_bytes?: number
local_peer?: PeerInfo
connected_peers?: PeerInfo[]
rooms?: string[]
networks?: NetworkInfo[]
error_message?: string
invite?: string
files?: FileEntry[]
}