Spaces:
Sleeping
Sleeping
File size: 6,453 Bytes
fdc7871 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | import React from 'react';
import { MessageSquare, Users, Mic, Activity, BarChart2 } from 'lucide-react';
import { Line } from 'react-chartjs-2';
export default function OverviewTab({
statsSummary,
selectedStreamId,
activityData,
isRacing,
startGraphRace,
chartDataConfig,
chartOptions,
voiceWords
}) {
return (
<div className="tab-content">
{/* Stats row */}
<div className="grid-4col" style={{ marginBottom: '2rem' }}>
<div className="stat-card" style={{ '--accent-color': 'var(--color-brand)' }}>
<div className="stat-card-inner">
<div style={{ minWidth: 0, flex: 1, marginRight: '0.5rem' }}>
<div className="stat-label">Сообщений в чате</div>
<div className="stat-value">{statsSummary.messages.toLocaleString()}</div>
</div>
<div className="stat-icon-wrapper">
<MessageSquare size={22} style={{ color: 'var(--color-brand)' }} />
</div>
</div>
</div>
<div className="stat-card" style={{ '--accent-color': 'var(--color-text-accent)' }}>
<div className="stat-card-inner">
<div style={{ minWidth: 0, flex: 1, marginRight: '0.5rem' }}>
<div className="stat-label">Уникальных зрителей</div>
<div className="stat-value">{statsSummary.uniqueChatters.toLocaleString()}</div>
</div>
<div className="stat-icon-wrapper">
<Users size={22} style={{ color: 'var(--color-text-accent)' }} />
</div>
</div>
</div>
<div className="stat-card" style={{ '--accent-color': '#ff007f' }}>
<div className="stat-card-inner">
<div style={{ minWidth: 0, flex: 1, marginRight: '0.5rem' }}>
<div className="stat-label">Самый активный чатер</div>
<div
className="stat-value"
title={statsSummary.mostActiveChatter || ''}
style={{
fontSize: (statsSummary.mostActiveChatter || '').length > 15 ? '1.05rem' : '1.25rem',
letterSpacing: '-0.02em',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}
>
{statsSummary.mostActiveChatter || '—'}
</div>
</div>
<div className="stat-icon-wrapper">
<Users size={22} style={{ color: '#ff007f' }} />
</div>
</div>
</div>
<div className="stat-card" style={{ '--accent-color': '#00f5d4' }}>
<div className="stat-card-inner">
<div style={{ minWidth: 0, flex: 1, marginRight: '0.5rem' }}>
<div className="stat-label">Распознано слов (голос)</div>
<div className="stat-value">{statsSummary.voiceWordsCount.toLocaleString()}</div>
</div>
<div className="stat-icon-wrapper">
<Mic size={22} style={{ color: '#00f5d4' }} />
</div>
</div>
</div>
</div>
<div className="grid-2col" style={{ gridTemplateColumns: '2fr 1fr' }}>
{/* Activity graph */}
<div className="panel">
<div className="panel-header">
<h3 className="panel-title"><Activity size={20} /> Активность чата</h3>
<div style={{ display: 'flex', gap: '0.75rem', alignItems: 'center' }}>
<span style={{ fontSize: '0.8rem', color: 'var(--color-text-muted)' }}>выберите конкретный стрим для графика</span>
{activityData.length > 0 && (
<button
className="btn btn-secondary"
style={{ fontSize: '0.75rem', padding: '0.3rem 0.6rem' }}
onClick={startGraphRace}
disabled={isRacing}
>
<Activity size={12} className={isRacing ? "pulse" : ""} /> {isRacing ? 'Гонка идет...' : 'Запустить гонку'}
</button>
)}
</div>
</div>
{selectedStreamId === 'all' ? (
<div className="status-msg" style={{ height: '300px' }}>
<BarChart2 size={36} className="status-msg-icon" />
<p>Для просмотра временного графика выберите конкретный стрим в верхнем меню</p>
</div>
) : activityData.length === 0 ? (
<div className="status-msg" style={{ height: '300px' }}>
<MessageSquare size={36} className="status-msg-icon" />
<p>В этом стриме пока не было сообщений</p>
</div>
) : (
<div className="chart-container">
<Line data={chartDataConfig} options={chartOptions} />
</div>
)}
</div>
{/* Quick Words list */}
<div className="panel">
<div className="panel-header">
<h3 className="panel-title">
<Mic size={18} style={{ color: 'var(--color-text-accent)' }} /> Голос стримера (Топ)
</h3>
</div>
{voiceWords.length === 0 ? (
<div className="status-msg" style={{ height: '300px', padding: '1rem' }}>
<Mic size={28} className="status-msg-icon" />
<p>Слова пока не распознаны. Запустите local_worker на ПК.</p>
</div>
) : (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', maxHeight: '320px', overflowY: 'auto', paddingRight: '4px' }}>
{voiceWords.slice(0, 7).map((w, idx) => (
<div key={idx} style={{ display: 'flex', justifyContent: 'space-between', padding: '0.5rem 0.75rem', backgroundColor: 'var(--color-bg-base)', border: '1px solid var(--color-border)', borderRadius: '6px', alignItems: 'center' }}>
<span style={{ fontWeight: 600, color: 'var(--color-text-main)' }}>#{idx+1} {w.word}</span>
<span className="badge badge-streamer">{w.word_count} раз</span>
</div>
))}
</div>
)}
</div>
</div>
</div>
);
}
|