mirror of
https://github.com/yusufipk/YTChatHub.git
synced 2026-09-11 19:06:14 +00:00
Rewrite dashboard and overlay, single /events stream, static client served by the backend
Backend: one SSE stream for messages, selection, poll and connection status; reconnect with backoff; no on-disk Innertube session cache; mock only with MOCK_CHAT=1; binds to 127.0.0.1; serves client/out so production runs on one port. Full URLs for links YouTube truncates in chat. Client: components split out, Lucide icons, stream title and status, on-air strip, search, pause, keyboard shortcuts, overlay settings dialog. Overlay themes, position, size, animation and auto-hide via URL, sized for 1080p and scaled with the source. New blueprint theme for the brand background. Removed Tailwind, better-sqlite3, zod, the timezone helpers, Cline memory bank and AGENTS.md. Added ESLint, node:test tests and CI.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
'use client';
|
||||
|
||||
import { X } from 'lucide-react';
|
||||
import type { ChatMessage } from '@shared/chat';
|
||||
import { proxyImageUrl } from '../lib/imageProxy';
|
||||
import { formatAmount } from '../lib/format';
|
||||
import { MessageBody } from './MessageBody';
|
||||
|
||||
type Props = { selection: ChatMessage | null; onClear: () => void };
|
||||
|
||||
/** Mirrors what the OBS overlay is showing right now, so the operator never has to guess. */
|
||||
export function OnAir({ selection, onClear }: Props) {
|
||||
return (
|
||||
<section className={`onair ${selection ? 'onair--live' : ''}`}>
|
||||
<span className="onair__label">On air</span>
|
||||
{selection ? (
|
||||
<>
|
||||
{selection.authorPhoto && <img src={proxyImageUrl(selection.authorPhoto)} alt="" className="avatar avatar--sm" />}
|
||||
<span className="onair__author">{selection.author}</span>
|
||||
{selection.superChat && (
|
||||
<span className="card__amount" style={{ background: selection.superChat.color }}>
|
||||
{formatAmount(selection.superChat.amount, selection.superChat.currency)}
|
||||
</span>
|
||||
)}
|
||||
<MessageBody message={selection} className="onair__text" />
|
||||
<button type="button" className="btn btn--sm" onClick={onClear} title="Clear the overlay (Esc)">
|
||||
<X size={13} />
|
||||
Clear
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<span className="onair__hint">Nothing on the overlay. Click a message to show it, click again to hide it.</span>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user