Spaces:
Sleeping
Sleeping
| 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> | |
| ); | |
| } | |