feat: implement main dashboard UI with file upload, configuration, and transcription progress tracking

This commit is contained in:
Ümit Tunç
2026-04-23 08:58:41 +03:00
parent 9cf716168c
commit a720260c30
+24 -24
View File
@@ -1,11 +1,11 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { import {
LayoutDashboard, LayoutDashboard,
Box, Box,
ListMusic, ListMusic,
Settings, Settings,
X, X,
Minus, Minus,
Square, Square,
UploadCloud, UploadCloud,
ChevronDown, ChevronDown,
@@ -56,7 +56,7 @@ function App() {
return return
} }
window.api.detectHardware().then(setHardware) window.api.detectHardware().then(setHardware)
window.api.onTranscriptionProgress((p) => { window.api.onTranscriptionProgress((p) => {
setProgress(p) setProgress(p)
}) })
@@ -105,7 +105,7 @@ function App() {
if (!file) return if (!file) return
setIsTranscribing(true) setIsTranscribing(true)
setProgress(0) setProgress(0)
try { try {
const result = await window.api.startTranscription(file.path, config) const result = await window.api.startTranscription(file.path, config)
if (result.success) { if (result.success) {
@@ -133,12 +133,12 @@ function App() {
{/* Header */} {/* Header */}
<header className="header"> <header className="header">
<div className="logo-section"> <div className="logo-section">
<img src={logo} alt="Voicext Logo" style={{ height: '32px' }} /> <img src={logo} alt="Voicext Logo" style={{ height: '128px' }} />
</div> </div>
<nav className="nav-tabs"> <nav className="nav-tabs">
{['dashboard', 'models', 'queue', 'settings'].map((tab) => ( {['dashboard', 'models', 'queue', 'settings'].map((tab) => (
<div <div
key={tab} key={tab}
className={`nav-item ${activeTab === tab ? 'active' : ''}`} className={`nav-item ${activeTab === tab ? 'active' : ''}`}
onClick={() => setActiveTab(tab)} onClick={() => setActiveTab(tab)}
@@ -156,14 +156,14 @@ function App() {
{/* Content Area */} {/* Content Area */}
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
{activeTab === 'dashboard' && ( {activeTab === 'dashboard' && (
<motion.div <motion.div
key="dashboard" key="dashboard"
initial={{ opacity: 0, scale: 0.98 }} initial={{ opacity: 0, scale: 0.98 }}
animate={{ opacity: 1, scale: 1 }} animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 1.02 }} exit={{ opacity: 0, scale: 1.02 }}
className="dashboard-grid" className="dashboard-grid"
> >
<div <div
className={`drop-zone glass ${dragActive ? 'drag-active' : ''}`} className={`drop-zone glass ${dragActive ? 'drag-active' : ''}`}
onDragEnter={handleDrag} onDragEnter={handleDrag}
onDragLeave={handleDrag} onDragLeave={handleDrag}
@@ -176,8 +176,8 @@ function App() {
<div className="progress-circle"> <div className="progress-circle">
<svg width="120" height="120"> <svg width="120" height="120">
<circle cx="60" cy="60" r="54" fill="none" stroke="rgba(255,255,255,0.1)" strokeWidth="8" /> <circle cx="60" cy="60" r="54" fill="none" stroke="rgba(255,255,255,0.1)" strokeWidth="8" />
<motion.circle <motion.circle
cx="60" cy="60" r="54" fill="none" cx="60" cy="60" r="54" fill="none"
stroke="url(#gradient)" strokeWidth="8" stroke="url(#gradient)" strokeWidth="8"
strokeDasharray="339.29" strokeDasharray="339.29"
initial={{ strokeDashoffset: 339.29 }} initial={{ strokeDashoffset: 339.29 }}
@@ -206,8 +206,8 @@ function App() {
<div style={{ textAlign: 'center' }}> <div style={{ textAlign: 'center' }}>
<h2 style={{ fontSize: '20px', color: 'var(--primary-cyan)' }}>{file.name}</h2> <h2 style={{ fontSize: '20px', color: 'var(--primary-cyan)' }}>{file.name}</h2>
<p>File Ready for Transcription</p> <p>File Ready for Transcription</p>
<button <button
className="btn-secondary" className="btn-secondary"
onClick={(e) => { e.stopPropagation(); setFile(null); }} onClick={(e) => { e.stopPropagation(); setFile(null); }}
style={{ marginTop: '10px', background: 'none', border: '1px solid rgba(255,255,255,0.1)', color: '#666', padding: '5px 15px', borderRadius: '20px', cursor: 'pointer' }} style={{ marginTop: '10px', background: 'none', border: '1px solid rgba(255,255,255,0.1)', color: '#666', padding: '5px 15px', borderRadius: '20px', cursor: 'pointer' }}
> >
@@ -233,30 +233,30 @@ function App() {
<Monitor size={14} /> <Monitor size={14} />
Quick Configuration Quick Configuration
</div> </div>
<CustomSelect <CustomSelect
label="Language:" label="Language:"
options={languages} options={languages}
value={config.language} value={config.language}
onChange={(val) => setConfig({ ...config, language: val })} onChange={(val) => setConfig({ ...config, language: val })}
/> />
<CustomSelect <CustomSelect
label="Model:" label="Model:"
options={models} options={models}
value={config.model} value={config.model}
onChange={(val) => setConfig({ ...config, model: val })} onChange={(val) => setConfig({ ...config, model: val })}
/> />
<CustomSelect <CustomSelect
label="Format:" label="Format:"
options={formats} options={formats}
value={config.format} value={config.format}
onChange={(val) => setConfig({ ...config, format: val })} onChange={(val) => setConfig({ ...config, format: val })}
/> />
<button <button
className="btn-primary" className="btn-primary"
style={{ marginTop: '20px', opacity: file ? 1 : 0.5, cursor: file ? 'pointer' : 'not-allowed' }} style={{ marginTop: '20px', opacity: file ? 1 : 0.5, cursor: file ? 'pointer' : 'not-allowed' }}
disabled={!file || isTranscribing} disabled={!file || isTranscribing}
onClick={startTranscription} onClick={startTranscription}
@@ -269,7 +269,7 @@ function App() {
)} )}
{activeTab === 'models' && ( {activeTab === 'models' && (
<motion.div <motion.div
key="models" key="models"
initial={{ opacity: 0, x: 20 }} initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}