veza/apps/web/src/components/live/LiveStreamDetailView.tsx
senke 8c3e7c1a36 ui(tokens): migrate border-kodo-steel to border-border (86 files, 269 instances)
Replace legacy hardcoded border-kodo-steel (RGB 59,69,84, theme-unaware)
with semantic border-border token across 86 user-facing components.

Covers UI primitives (checkbox, badge, modal, table, textarea, alert,
radio-group, avatar), all modals, settings views, social features,
playlist views, inventory, chat, commerce, and cloud file browser.

Only story/test files retain the legacy token.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 00:07:00 +01:00

231 lines
7.9 KiB
TypeScript

import React, { useState } from 'react';
import { Button } from '../ui/button';
import { LiveStream } from '../../types';
import {
Users,
Heart,
Share2,
DollarSign,
Send,
Radio,
Settings,
ArrowLeft,
} from 'lucide-react';
import { useToast } from '../../components/feedback/ToastProvider';
import { TipStreamerModal } from './modals/TipStreamerModal';
interface LiveStreamDetailViewProps {
streamId: string;
onBack: () => void;
}
// Mock Stream Data
const MOCK_STREAM: LiveStream = {
id: 's1',
title: 'Late Night DnB Production 🎧 | Feedback Session',
streamer: 'Neuro_Glitch',
viewers: 1240,
thumbnailUrl: 'https://picsum.photos/id/140/1200/800',
tags: ['Production', 'Ableton', 'DnB'],
isLive: true,
category: 'Production',
};
export const LiveStreamDetailView: React.FC<LiveStreamDetailViewProps> = ({
streamId: _streamId,
onBack,
}) => {
const { addToast } = useToast();
const [chatInput, setChatInput] = useState('');
const [showTipModal, setShowTipModal] = useState(false);
const [messages, setMessages] = useState([
{
id: 1,
user: 'BassHead99',
text: 'That Reese bass is filthy! 🤮🔥',
color: 'text-kodo-cyan',
},
{
id: 2,
user: 'Studio_Rat',
text: 'What VST is that?',
color: 'text-muted-foreground',
},
{
id: 3,
user: 'Neuro_Glitch',
text: "It's Phase Plant, just initializing now.",
color: 'text-kodo-gold font-bold',
},
]);
const handleSendChat = () => {
if (!chatInput.trim()) return;
setMessages([
...messages,
{ id: Date.now(), user: 'You', text: chatInput, color: 'text-white' },
]);
setChatInput('');
};
const handleTip = (amount: number, message: string) => {
addToast(`Sent $${amount} to ${MOCK_STREAM.streamer}`, 'success');
setMessages([
...messages,
{
id: Date.now(),
user: 'System',
text: `You tipped $${amount}: ${message}`,
color: 'text-kodo-lime font-bold italic',
},
]);
};
return (
<div className="flex flex-col h-[calc(100vh-6rem)] -m-6 md:-m-12 bg-black animate-fadeIn overflow-hidden">
{/* Header Overlay (Fade in/out logic usually here) */}
<div className="absolute top-0 left-0 right-0 p-4 z-20 flex justify-between items-start pointer-events-none">
<Button
variant="ghost"
size="sm"
className="bg-black/50 backdrop-blur pointer-events-auto text-white hover:bg-black/70"
onClick={onBack}
>
<ArrowLeft className="w-4 h-4 mr-2" /> Back
</Button>
</div>
<div className="flex flex-1 overflow-hidden">
{/* Video Player Area */}
<div className="flex-1 bg-black relative flex items-center justify-center">
{/* Simulated Video */}
<div className="absolute inset-0">
<img
src={MOCK_STREAM.thumbnailUrl}
className="w-full h-full object-cover opacity-80"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black via-transparent to-black/30"></div>
</div>
{/* Stream Info Overlay */}
<div className="absolute bottom-0 left-0 right-0 p-6 bg-gradient-to-t from-black to-transparent pt-24">
<div className="flex items-end justify-between">
<div className="flex items-center gap-4">
<div className="w-14 h-14 rounded-full border-2 border-kodo-red p-0.5">
<img
src="https://picsum.photos/id/100/100"
className="w-full h-full rounded-full object-cover"
/>
</div>
<div>
<h1 className="text-3xl font-bold text-white mb-1">
{MOCK_STREAM.title}
</h1>
<div className="flex items-center gap-4 text-sm">
<span className="text-kodo-steel font-bold">
{MOCK_STREAM.streamer}
</span>
<span className="flex items-center gap-1 text-kodo-red font-bold animate-pulse">
<Radio className="w-3 h-3" /> LIVE
</span>
<span className="flex items-center gap-1 text-white">
<Users className="w-3 h-3" />{' '}
{MOCK_STREAM.viewers.toLocaleString()}
</span>
</div>
</div>
</div>
<div className="flex gap-4">
<Button
variant="secondary"
className="bg-black/50 backdrop-blur border-white/20 text-white"
icon={<Heart className="w-4 h-4" />}
>
Follow
</Button>
<Button
variant="primary"
className=""
icon={<DollarSign className="w-4 h-4" />}
onClick={() => setShowTipModal(true)}
>
Tip
</Button>
<Button
variant="ghost"
size="icon"
className="bg-black/50 backdrop-blur text-white"
>
<Share2 className="w-4 h-4" />
</Button>
</div>
</div>
</div>
</div>
{/* Chat Sidebar */}
<div className="w-80 md:w-96 bg-kodo-graphite border-l border-border flex flex-col z-20 shadow-2xl">
<div className="p-4 border-b border-border bg-kodo-ink flex justify-between items-center">
<h3 className="font-bold text-white text-sm">LIVE CHAT</h3>
<Settings className="w-4 h-4 text-muted-foreground cursor-pointer hover:text-white" />
</div>
<div className="flex-1 overflow-y-auto p-4 space-y-2 font-mono text-sm custom-scrollbar">
{messages.map((msg) => (
<div key={msg.id} className="break-words animate-slideInRight">
<span
className={`font-bold ${msg.color} mr-2 cursor-pointer hover:underline opacity-90`}
>
{msg.user}:
</span>
<span className="text-kodo-text-main">{msg.text}</span>
</div>
))}
</div>
<div className="p-4 border-t border-border bg-kodo-ink">
<div className="relative">
<input
className="w-full bg-kodo-void border border-border rounded-full py-2.5 pl-4 pr-10 text-white text-sm focus:border-border outline-none"
placeholder="Send a message..."
value={chatInput}
onChange={(e) => setChatInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSendChat()}
/>
<Button
variant="default"
size="icon"
className="absolute right-1.5 top-1.5 rounded-full hover:bg-white"
onClick={handleSendChat}
>
<Send className="w-3 h-3 fill-current" />
</Button>
</div>
<div className="flex justify-between items-center mt-2 px-2">
<span className="text-xs text-muted-foreground">Slow Mode: Off</span>
<div className="flex gap-2">
<Button
variant="ghost"
size="icon"
className="text-kodo-gold hover:text-white"
title="Send Tip"
onClick={() => setShowTipModal(true)}
>
<DollarSign className="w-4 h-4" />
</Button>
</div>
</div>
</div>
</div>
</div>
{showTipModal && (
<TipStreamerModal
streamerName={MOCK_STREAM.streamer}
onClose={() => setShowTipModal(false)}
onSend={handleTip}
/>
)}
</div>
);
};