Files
office_translator/stitch_translation_app_ui_redesign/preview-translate.html
sepehr b50419e2ec
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2s
fix: integrate deepseek, resolve silent google api errors, fix google cloud keys
2026-05-17 17:11:06 +02:00

1110 lines
64 KiB
HTML

<!DOCTYPE html>
<html class="light" lang="en"><head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>LinguistPro - Translation Workspace</title>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
<script>
tailwind.config = {
darkMode: "class",
theme: {
extend: {
"colors": {
"on-secondary": "#ffffff",
"on-primary-container": "#eeefff",
"on-secondary-container": "#54647a",
"surface-tint": "#0053db",
"tertiary-container": "#656d84",
"on-primary-fixed": "#00174b",
"on-error-container": "#93000a",
"secondary-fixed-dim": "#b7c8e1",
"on-error": "#ffffff",
"inverse-surface": "#2e3132",
"primary-fixed": "#dbe1ff",
"on-tertiary-container": "#eef0ff",
"primary-container": "#2563eb",
"on-tertiary": "#ffffff",
"surface-bright": "#f8f9fa",
"on-tertiary-fixed-variant": "#3f465c",
"surface-container-lowest": "#ffffff",
"on-secondary-fixed": "#0b1c30",
"inverse-primary": "#b4c5ff",
"surface-container-high": "#e7e8e9",
"secondary-container": "#d0e1fb",
"secondary-fixed": "#d3e4fe",
"surface-dim": "#d9dadb",
"error": "#ba1a1a",
"outline-variant": "#c3c6d7",
"on-secondary-fixed-variant": "#38485d",
"surface-container-low": "#f3f4f5",
"primary-fixed-dim": "#b4c5ff",
"on-background": "#191c1d",
"surface": "#f8f9fa",
"on-surface-variant": "#434655",
"on-primary-fixed-variant": "#003ea8",
"secondary": "#505f76",
"on-tertiary-fixed": "#131b2e",
"background": "#f8f9fa",
"outline": "#737686",
"primary": "#004ac6",
"on-primary": "#ffffff",
"surface-variant": "#e1e3e4",
"tertiary-fixed": "#dae2fd",
"on-surface": "#191c1d",
"surface-container-highest": "#e1e3e4",
"inverse-on-surface": "#f0f1f2",
"error-container": "#ffdad6",
"tertiary-fixed-dim": "#bec6e0",
"tertiary": "#4d556b",
"surface-container": "#edeeef"
},
"borderRadius": {
DEFAULT: "0.125rem",
lg: "0.25rem",
xl: "0.5rem",
full: "0.75rem"
},
"spacing": {
xl: "32px",
unit: "4px",
sm: "8px",
lg: "24px",
xs: "4px",
"sidebar-width": "240px",
md: "16px",
"container-max": "1440px"
},
"fontFamily": {
h2: ["Inter"],
code: ["Monospace"],
h1: ["Inter"],
"body-md": ["Inter"],
"body-lg": ["Inter"],
"body-sm": ["Inter"],
"label-md": ["Inter"],
h3: ["Inter"]
},
"fontSize": {
h2: ["20px", { lineHeight: "28px", letterSpacing: "-0.01em", fontWeight: "600" }],
code: ["13px", { lineHeight: "20px", fontWeight: "400" }],
h1: ["24px", { lineHeight: "32px", letterSpacing: "-0.02em", fontWeight: "600" }],
"body-md": ["14px", { lineHeight: "20px", fontWeight: "400" }],
"body-lg": ["16px", { lineHeight: "24px", fontWeight: "400" }],
"body-sm": ["13px", { lineHeight: "18px", fontWeight: "400" }],
"label-md": ["12px", { lineHeight: "16px", letterSpacing: "0.05em", fontWeight: "500" }],
h3: ["16px", { lineHeight: "24px", fontWeight: "600" }]
}
}
}
}
</script>
<style>
/* Combobox style */
.combobox-wrapper { position: relative; }
.combobox-trigger {
display: flex; align-items: center; justify-content: space-between;
width: 100%; padding: 8px 12px; padding-right: 32px;
background: #ffffff; border: 1px solid #c3c6d7; border-radius: 8px;
font-size: 14px; color: #191c1d; cursor: pointer;
transition: border-color 0.15s, box-shadow 0.15s;
font-family: Inter, sans-serif; line-height: 20px;
}
.combobox-trigger:hover { border-color: #737686; }
.combobox-trigger:focus, .combobox-trigger.active { border-color: #2563eb; box-shadow: 0 0 0 2px rgba(37,99,235,0.15); outline: none; }
.combobox-trigger .chevron { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); transition: transform 0.15s; pointer-events: none; color: #737686; font-size: 18px; }
.combobox-trigger.active .chevron { transform: translateY(-50%) rotate(180deg); }
.combobox-dropdown {
position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 100;
background: #ffffff; border: 1px solid #c3c6d7; border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1); display: none; overflow: hidden;
}
.combobox-dropdown.open { display: block; }
.combobox-search {
width: 100%; padding: 8px 12px; border: none; border-bottom: 1px solid #e1e3e4;
font-size: 13px; outline: none; font-family: Inter, sans-serif; color: #191c1d;
}
.combobox-list { max-height: 200px; overflow-y: auto; padding: 4px; }
.combobox-option {
display: flex; align-items: center; gap: 8px; width: 100%;
padding: 8px 12px; border: none; background: none; cursor: pointer;
font-size: 14px; color: #191c1d; border-radius: 6px; text-align: left;
font-family: Inter, sans-serif; line-height: 20px;
}
.combobox-option:hover { background: #dbe1ff; }
.combobox-option.selected { background: #dbe1ff; color: #004ac6; font-weight: 500; }
.combobox-option .check { margin-left: auto; color: #2563eb; font-size: 16px; }
.combobox-option .check.hidden { display: none; }
/* Progress animation */
@keyframes progress-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.6; } }
.progress-pulse { animation: progress-pulse 2s ease-in-out infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.spin { animation: spin 1s linear infinite; }
/* Gradient progress bar */
@keyframes progress-shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.progress-shimmer {
background: linear-gradient(90deg, #004ac6 0%, #2563eb 30%, #4f8bff 50%, #2563eb 70%, #004ac6 100%);
background-size: 200% 100%;
animation: progress-shimmer 2s linear infinite;
}
/* Stepper */
.step-line { height: 2px; transition: background-color 0.4s ease; }
.step-circle {
width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
transition: all 0.4s ease; flex-shrink: 0;
}
.step-label { transition: color 0.4s ease; }
/* State toggle */
.state-btn { transition: all 0.15s; }
.state-btn.active { background: #004ac6; color: #fff; }
/* Card transition */
.card-transition { transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); }
/* Activity feed */
@keyframes slideIn {
from { opacity: 0; transform: translateY(-8px); }
to { opacity: 1; transform: translateY(0); }
}
.activity-item { animation: slideIn 0.3s ease-out; }
/* Stat counter */
@keyframes countUp {
from { opacity: 0.5; }
to { opacity: 1; }
}
.stat-value { transition: all 0.3s ease; }
/* Success celebration */
@keyframes successBounce {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
.success-bounce { animation: successBounce 0.6s ease-in-out; }
@keyframes checkDraw {
from { stroke-dashoffset: 24; }
to { stroke-dashoffset: 0; }
}
/* Elapsed time pulse */
.elapsed-dot {
width: 6px; height: 6px; border-radius: 50%; background: #004ac6;
animation: progress-pulse 1.5s ease-in-out infinite;
}
</style>
</head>
<body class="bg-background text-on-background font-body-md text-body-md min-h-screen flex">
<!-- SideNavBar -->
<nav class="h-screen w-64 border-r fixed left-0 top-0 border-r border-slate-200 dark:border-slate-800 bg-slate-50 dark:bg-slate-900 font-sans text-sm font-medium tracking-tight flex flex-col h-full py-4 z-50">
<div class="px-6 pb-6 border-b border-slate-200 dark:border-slate-800 mb-4">
<h1 class="text-lg font-bold text-slate-900 dark:text-white truncate">LinguistPro</h1>
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">Enterprise Tier</p>
</div>
<div class="px-4 mb-6">
<button class="w-full py-2.5 px-4 bg-primary text-on-primary rounded-lg font-label-md text-label-md flex items-center justify-center gap-2 hover:opacity-90 transition-opacity shadow-[0px_4px_6px_-1px_rgba(0,0,0,0.1)]">
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">add</span>
New Translation
</button>
</div>
<ul class="flex-1 space-y-1">
<li><a class="flex items-center gap-3 px-4 py-2 border-l-2 border-blue-600 bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" href="#"><span class="material-symbols-outlined">translate</span>Workspace</a></li>
<li><a class="flex items-center gap-3 px-4 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" href="#"><span class="material-symbols-outlined">folder_open</span>Projects</a></li>
<li><a class="flex items-center gap-3 px-4 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover-slate-800 transition-colors" href="#"><span class="material-symbols-outlined">book</span>Glossary</a></li>
<li><a class="flex items-center gap-3 px-4 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" href="#"><span class="material-symbols-outlined">group</span>Team</a></li>
<li><a class="flex items-center gap-3 px-4 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" href="#"><span class="material-symbols-outlined">settings</span>Settings</a></li>
</ul>
<div class="mt-auto border-t border-slate-200 dark:border-slate-800 pt-4">
<ul class="space-y-1">
<li><a class="flex items-center gap-3 px-4 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" href="#"><span class="material-symbols-outlined">help</span>Help Center</a></li>
<li><a class="flex items-center gap-3 px-4 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" href="#"><span class="material-symbols-outlined">account_circle</span>Account</a></li>
</ul>
</div>
</nav>
<!-- Main Content Area -->
<div class="flex-1 ml-[256px] flex flex-col h-screen overflow-hidden">
<!-- TopNavBar -->
<header class="sticky top-0 z-40 border-b border-slate-200 dark:border-slate-800 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md font-sans text-sm font-semibold flex justify-between items-center h-16 px-8">
<div class="flex items-center gap-8">
<span class="text-xl font-black text-slate-900 dark:text-white">Translation Workspace</span>
<nav class="hidden md:flex gap-6 h-full items-center">
<a class="text-slate-600 dark:text-slate-400 hover:text-blue-700 dark:hover:text-blue-300 h-full flex items-center border-b-2 border-transparent" href="#">Documents</a>
<a class="text-slate-600 dark:text-slate-400 hover:text-blue-700 dark:hover:text-blue-300 h-full flex items-center border-b-2 border-transparent" href="#">API</a>
<a class="text-slate-600 dark:text-slate-400 hover:text-blue-700 dark:hover:text-blue-300 h-full flex items-center border-b-2 border-transparent" href="#">History</a>
</nav>
</div>
<div class="flex items-center gap-4">
<div class="relative hidden sm:block">
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" style="font-size: 18px;">search</span>
<input class="pl-9 pr-4 py-1.5 bg-slate-100 border-transparent rounded-lg text-sm focus:border-blue-500 focus:bg-white focus:ring-0 w-64 transition-colors" placeholder="Search workspace..." type="text"/>
</div>
<div class="flex items-center gap-2 border-l border-slate-200 pl-4 ml-2">
<button class="p-2 text-slate-600 hover:bg-slate-100 rounded-full transition-colors relative"><span class="material-symbols-outlined">notifications</span><span class="absolute top-1.5 right-1.5 w-2 h-2 bg-blue-600 rounded-full border border-white"></span></button>
<button class="p-2 text-slate-600 hover:bg-slate-100 rounded-full transition-colors"><span class="material-symbols-outlined">help_outline</span></button>
<button class="ml-2 w-8 h-8 rounded-full overflow-hidden border border-slate-200 hover:border-blue-500 transition-colors bg-blue-100 flex items-center justify-center text-blue-600 font-bold text-sm">SP</button>
</div>
</div>
</header>
<!-- Page Canvas -->
<main class="flex-1 overflow-y-auto p-8 bg-surface-bright">
<div class="max-w-[1200px] mx-auto space-y-6">
<!-- ═══════════════════════════════════════════════════ -->
<!-- STATE 1: Upload + Config -->
<!-- ═══════════════════════════════════════════════════ -->
<div id="state-upload">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Left: Source Document card -->
<div id="card-source" class="lg:col-span-2 bg-surface-container-lowest border border-surface-variant rounded-xl p-6 shadow-sm">
<h2 class="font-h2 text-h2 text-on-surface mb-4">Source Document</h2>
<!-- Dropzone -->
<div id="dropzone" class="border-2 border-dashed border-outline-variant rounded-lg p-8 flex flex-col items-center justify-center text-center bg-surface hover:border-primary transition-colors cursor-pointer group" onclick="simulateUpload()">
<div class="w-12 h-12 bg-primary-fixed rounded-full flex items-center justify-center text-primary mb-3 group-hover:scale-110 transition-transform">
<span class="material-symbols-outlined" style="font-size: 24px;">upload_file</span>
</div>
<p class="font-body-lg text-body-lg text-on-surface font-medium mb-1">Drag and drop file here</p>
<p class="font-body-sm text-body-sm text-on-surface-variant mb-4">Supports .docx, .xlsx, .pptx (Max 50MB)</p>
<button class="px-4 py-2 bg-white border border-surface-variant rounded-lg font-label-md text-label-md text-on-surface hover:bg-surface-container-low transition-colors shadow-sm">
Browse Files
</button>
</div>
<!-- File info (hidden by default) -->
<div id="file-info" class="hidden">
<div class="flex items-center gap-3 p-4 rounded-lg border border-surface-variant bg-surface mb-4">
<span class="material-symbols-outlined text-blue-500" style="font-size: 28px;">description</span>
<div class="flex-1 min-w-0">
<p class="font-medium text-on-surface truncate">marketing_copy_v2.docx</p>
<p class="text-xs text-on-surface-variant">245 KB · Word Document</p>
</div>
<button class="p-2 text-on-surface-variant hover:text-error transition-colors" onclick="resetState()">
<span class="material-symbols-outlined" style="font-size: 20px;">close</span>
</button>
</div>
<div class="text-center text-xs text-on-surface-variant py-6">
Document ready for translation. Configure settings and click Start.
</div>
</div>
</div>
<!-- Right: Configuration card -->
<div id="card-config" class="bg-surface-container-lowest border border-surface-variant rounded-xl p-6 shadow-sm flex flex-col">
<h2 class="font-h2 text-h2 text-on-surface mb-4">Configuration</h2>
<div class="space-y-4 flex-1">
<!-- Source Language Combobox -->
<div>
<label class="block font-label-md text-label-md text-on-surface-variant mb-1.5">SOURCE LANGUAGE</label>
<div class="combobox-wrapper" data-id="source">
<button class="combobox-trigger" onclick="toggleDropdown('source')">
<span class="selected-text">Auto-detect</span>
<span class="material-symbols-outlined chevron" style="font-size: 18px;">expand_more</span>
</button>
<div class="combobox-dropdown" id="dd-source">
<input class="combobox-search" placeholder="Search languages..." oninput="filterOptions('source', this.value)"/>
<div class="combobox-list">
<button class="combobox-option selected" onclick="selectOption('source','Auto-detect','auto')"><span>Auto-detect</span><span class="material-symbols-outlined check" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('source','English (US)','en')"><span>English (US)</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('source','Français','fr')"><span>Français</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('source','Deutsch','de')"><span>Deutsch</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('source','Español','es')"><span>Español</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('source','Italiano','it')"><span>Italiano</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('source','Português','pt')"><span>Português</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
</div>
</div>
</div>
</div>
<!-- Swap -->
<div class="flex justify-center -my-1 relative z-10">
<button class="w-8 h-8 bg-surface-container-lowest border border-surface-variant rounded-full flex items-center justify-center text-on-surface-variant hover:text-primary hover:border-primary transition-colors shadow-sm bg-white" onclick="swapLanguages()">
<span class="material-symbols-outlined" style="font-size: 18px;">swap_vert</span>
</button>
</div>
<!-- Target Language Combobox -->
<div>
<label class="block font-label-md text-label-md text-on-surface-variant mb-1.5">TARGET LANGUAGE</label>
<div class="combobox-wrapper" data-id="target">
<button class="combobox-trigger" onclick="toggleDropdown('target')">
<span class="selected-text">Français</span>
<span class="material-symbols-outlined chevron" style="font-size: 18px;">expand_more</span>
</button>
<div class="combobox-dropdown" id="dd-target">
<input class="combobox-search" placeholder="Search languages..." oninput="filterOptions('target', this.value)"/>
<div class="combobox-list">
<button class="combobox-option selected" onclick="selectOption('target','Français','fr')"><span>Français</span><span class="material-symbols-outlined check" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('target','English (US)','en')"><span>English (US)</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('target','Deutsch','de')"><span>Deutsch</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('target','Español','es')"><span>Español</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('target','Italiano','it')"><span>Italiano</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('target','日本語','ja')"><span>日本語</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('target','中文','zh')"><span>中文</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('target','فارسی','fa')"><span>فارسی</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
</div>
</div>
</div>
</div>
<!-- Engine Combobox -->
<div>
<label class="block font-label-md text-label-md text-on-surface-variant mb-1.5">TRANSLATION ENGINE</label>
<div class="combobox-wrapper" data-id="engine">
<button class="combobox-trigger" onclick="toggleDropdown('engine')">
<span class="selected-text">Google Traduction</span>
<span class="material-symbols-outlined chevron" style="font-size: 18px;">expand_more</span>
</button>
<div class="combobox-dropdown" id="dd-engine">
<div class="combobox-list">
<button class="combobox-option selected" onclick="selectOption('engine','Google Traduction','google')"><span>Google Traduction</span><span class="material-symbols-outlined check" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('engine','DeepL','deepl')"><span>DeepL</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
<button class="combobox-option" onclick="selectOption('engine','Neural Machine Translation (Pro)','nmt')"><span>Neural Machine Translation (Pro)</span><span class="material-symbols-outlined check hidden" style="font-size: 16px;">check</span></button>
</div>
</div>
</div>
</div>
</div>
<button class="w-full mt-6 py-2.5 bg-primary text-on-primary rounded-lg font-label-md text-label-md flex items-center justify-center gap-2 hover:opacity-90 transition-opacity shadow-[0px_4px_6px_-1px_rgba(0,0,0,0.1)]" onclick="startTranslation()">
<span class="material-symbols-outlined" style="font-size: 18px;">bolt</span>
Start Translation
</button>
</div>
</div>
<!-- Recent Translations table -->
<div class="bg-surface-container-lowest border border-surface-variant rounded-xl shadow-sm overflow-hidden flex flex-col">
<div class="p-6 border-b border-surface-variant flex justify-between items-center bg-white">
<h2 class="font-h2 text-h2 text-on-surface flex items-center gap-2">
<span class="material-symbols-outlined text-primary">history</span>
Recent Translations
</h2>
<div class="flex gap-2">
<button class="p-1.5 text-on-surface-variant hover:bg-surface-container-low rounded transition-colors border border-transparent hover:border-surface-variant">
<span class="material-symbols-outlined" style="font-size: 20px;">filter_list</span>
</button>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-surface font-label-md text-label-md text-on-surface-variant border-b border-surface-variant">
<th class="px-6 py-3 font-medium">File Name</th>
<th class="px-6 py-3 font-medium">Languages</th>
<th class="px-6 py-3 font-medium">Status</th>
<th class="px-6 py-3 font-medium">Date</th>
<th class="px-6 py-3 font-medium text-right">Action</th>
</tr>
</thead>
<tbody class="font-body-md text-body-md text-on-surface divide-y divide-surface-variant bg-white">
<tr class="hover:bg-surface-container-lowest transition-colors group">
<td class="px-6 py-4"><div class="flex items-center gap-3"><span class="material-symbols-outlined text-tertiary-container">description</span><span class="font-medium text-on-surface">marketing_copy_v2.docx</span></div></td>
<td class="px-6 py-4"><div class="flex items-center gap-2 text-sm"><span class="px-2 py-0.5 bg-surface-container rounded text-on-surface-variant">EN</span><span class="material-symbols-outlined text-outline" style="font-size: 16px;">arrow_right_alt</span><span class="px-2 py-0.5 bg-primary-fixed rounded text-on-primary-fixed">FR</span></div></td>
<td class="px-6 py-4"><span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-[#ecfdf5] text-[#065f46]"><span class="w-1.5 h-1.5 rounded-full bg-[#10b981]"></span>Completed</span></td>
<td class="px-6 py-4 text-on-surface-variant text-sm">Today, 10:42 AM</td>
<td class="px-6 py-4 text-right"><button class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-white border border-surface-variant rounded-md text-sm font-medium text-primary hover:bg-primary-fixed transition-colors opacity-0 group-hover:opacity-100 focus:opacity-100"><span class="material-symbols-outlined" style="font-size: 16px;">download</span>Download</button></td>
</tr>
<tr class="hover:bg-surface-container-lowest transition-colors group">
<td class="px-6 py-4"><div class="flex items-center gap-3"><span class="material-symbols-outlined text-tertiary-container">data_object</span><span class="font-medium text-on-surface">ui_strings_core.json</span></div></td>
<td class="px-6 py-4"><div class="flex items-center gap-2 text-sm"><span class="px-2 py-0.5 bg-surface-container rounded text-on-surface-variant">EN</span><span class="material-symbols-outlined text-outline" style="font-size: 16px;">arrow_right_alt</span><span class="px-2 py-0.5 bg-primary-fixed rounded text-on-primary-fixed">DE</span></div></td>
<td class="px-6 py-4"><div class="flex items-center gap-2 w-32"><div class="h-1.5 w-full bg-surface-variant rounded-full overflow-hidden"><div class="h-full bg-primary w-2/3 rounded-full"></div></div><span class="text-xs text-on-surface-variant font-medium">65%</span></div></td>
<td class="px-6 py-4 text-on-surface-variant text-sm">Today, 09:15 AM</td>
<td class="px-6 py-4 text-right"><button class="inline-flex items-center p-1.5 text-on-surface-variant hover:text-primary transition-colors opacity-0 group-hover:opacity-100 focus:opacity-100" title="Cancel"><span class="material-symbols-outlined" style="font-size: 20px;">close</span></button></td>
</tr>
<tr class="hover:bg-surface-container-lowest transition-colors group">
<td class="px-6 py-4"><div class="flex items-center gap-3"><span class="material-symbols-outlined text-tertiary-container">description</span><span class="font-medium text-on-surface">legal_terms_2024.docx</span></div></td>
<td class="px-6 py-4"><div class="flex items-center gap-2 text-sm"><span class="px-2 py-0.5 bg-surface-container rounded text-on-surface-variant">EN</span><span class="material-symbols-outlined text-outline" style="font-size: 16px;">arrow_right_alt</span><span class="px-2 py-0.5 bg-primary-fixed rounded text-on-primary-fixed">ES</span></div></td>
<td class="px-6 py-4"><span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-[#ecfdf5] text-[#065f46]"><span class="w-1.5 h-1.5 rounded-full bg-[#10b981]"></span>Completed</span></td>
<td class="px-6 py-4 text-on-surface-variant text-sm">Yesterday</td>
<td class="px-6 py-4 text-right"><button class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-white border border-surface-variant rounded-md text-sm font-medium text-primary hover:bg-primary-fixed transition-colors opacity-0 group-hover:opacity-100 focus:opacity-100"><span class="material-symbols-outlined" style="font-size: 16px;">download</span>Download</button></td>
</tr>
</tbody>
</table>
</div>
<div class="p-4 border-t border-surface-variant bg-surface text-center">
<button class="text-sm font-medium text-primary hover:text-on-primary-fixed transition-colors">View All History</button>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════ -->
<!-- STATE 2: Translation in progress — REDESIGNED -->
<!-- The upload card is replaced by the progress card -->
<!-- The config card becomes a live monitoring panel -->
<!-- ═══════════════════════════════════════════════════════════════ -->
<div id="state-translating" class="hidden">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- ═══════════════════════════════════════════ -->
<!-- LEFT (2/3): Progress Card — replaces upload -->
<!-- ═══════════════════════════════════════════ -->
<div class="lg:col-span-2 bg-surface-container-lowest border border-surface-variant rounded-xl shadow-sm overflow-hidden">
<!-- Header band -->
<div class="bg-gradient-to-r from-primary/5 to-primary/10 border-b border-surface-variant px-6 py-4 flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-9 h-9 rounded-lg bg-primary/10 flex items-center justify-center">
<span class="material-symbols-outlined text-primary spin" style="font-size: 22px;">progress_activity</span>
</div>
<div>
<h2 class="font-h2 text-h2 text-on-surface leading-tight">Translation in Progress</h2>
<p class="text-xs text-on-surface-variant mt-0.5">marketing_copy_v2.docx</p>
</div>
</div>
<div class="flex items-center gap-1.5 text-xs text-primary font-semibold bg-primary/10 px-3 py-1.5 rounded-full">
<span class="material-symbols-outlined" style="font-size: 14px;">schedule</span>
<span id="progress-eta">Calculating...</span>
</div>
</div>
<div class="p-6 space-y-6">
<!-- ── Pipeline Stepper ── -->
<div class="flex items-center justify-between" id="pipeline-stepper">
<!-- Step 1: Upload -->
<div class="flex flex-col items-center gap-1.5 relative z-10" data-step="0">
<div class="step-circle bg-primary text-white shadow-md shadow-primary/20">
<span class="material-symbols-outlined" style="font-size: 18px;">upload_file</span>
</div>
<span class="step-label text-[11px] font-medium text-primary">Upload</span>
</div>
<div class="step-line flex-1 bg-primary -mx-1 relative top-[-10px]"></div>
<!-- Step 2: Analyse -->
<div class="flex flex-col items-center gap-1.5 relative z-10" data-step="1">
<div class="step-circle bg-surface-variant text-on-surface-variant">
<span class="material-symbols-outlined" style="font-size: 18px;">search_insights</span>
</div>
<span class="step-label text-[11px] font-medium text-on-surface-variant">Analyse</span>
</div>
<div class="step-line flex-1 bg-surface-variant -mx-1 relative top-[-10px]"></div>
<!-- Step 3: Traduction -->
<div class="flex flex-col items-center gap-1.5 relative z-10" data-step="2">
<div class="step-circle bg-surface-variant text-on-surface-variant">
<span class="material-symbols-outlined" style="font-size: 18px;">translate</span>
</div>
<span class="step-label text-[11px] font-medium text-on-surface-variant">Traduction</span>
</div>
<div class="step-line flex-1 bg-surface-variant -mx-1 relative top-[-10px]"></div>
<!-- Step 4: Reconstruction -->
<div class="flex flex-col items-center gap-1.5 relative z-10" data-step="3">
<div class="step-circle bg-surface-variant text-on-surface-variant">
<span class="material-symbols-outlined" style="font-size: 18px;">build</span>
</div>
<span class="step-label text-[11px] font-medium text-on-surface-variant">Reconstruction</span>
</div>
<div class="step-line flex-1 bg-surface-variant -mx-1 relative top-[-10px]"></div>
<!-- Step 5: Finalisation -->
<div class="flex flex-col items-center gap-1.5 relative z-10" data-step="4">
<div class="step-circle bg-surface-variant text-on-surface-variant">
<span class="material-symbols-outlined" style="font-size: 18px;">task_alt</span>
</div>
<span class="step-label text-[11px] font-medium text-on-surface-variant">Finalisation</span>
</div>
</div>
<!-- ── Progress Bar ── -->
<div class="space-y-2">
<div class="flex items-center justify-between">
<span id="progress-step" class="text-sm font-medium text-on-surface progress-pulse">Preparing document...</span>
<span id="progress-pct" class="text-2xl font-black text-primary tabular-nums tracking-tight">0%</span>
</div>
<div class="h-3 bg-surface-variant rounded-full overflow-hidden">
<div id="progress-bar" class="h-full rounded-full transition-all duration-700 ease-out progress-shimmer" style="width: 0%"></div>
</div>
</div>
<!-- ── Live Stats Grid ── -->
<div class="grid grid-cols-4 gap-3">
<div class="bg-surface rounded-xl p-3 text-center border border-surface-variant">
<span class="material-symbols-outlined text-primary mb-1" style="font-size: 20px;">segment</span>
<p id="stat-segments" class="text-lg font-bold text-on-surface tabular-nums stat-value">0</p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Segments</p>
</div>
<div class="bg-surface rounded-xl p-3 text-center border border-surface-variant">
<span class="material-symbols-outlined text-primary mb-1" style="font-size: 20px;">text_snippet</span>
<p id="stat-chars" class="text-lg font-bold text-on-surface tabular-nums stat-value">0</p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Characters</p>
</div>
<div class="bg-surface rounded-xl p-3 text-center border border-surface-variant">
<span class="material-symbols-outlined text-primary mb-1" style="font-size: 20px;">speed</span>
<p id="stat-speed" class="text-lg font-bold text-on-surface tabular-nums stat-value"></p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Seg/min</p>
</div>
<div class="bg-surface rounded-xl p-3 text-center border border-surface-variant">
<span class="material-symbols-outlined text-primary mb-1" style="font-size: 20px;">timer</span>
<p id="stat-elapsed" class="text-lg font-bold text-on-surface tabular-nums stat-value">0:00</p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Elapsed</p>
</div>
</div>
<!-- ── Activity Feed ── -->
<div>
<h3 class="text-xs font-semibold text-on-surface-variant uppercase tracking-wider mb-2 flex items-center gap-1.5">
<span class="material-symbols-outlined" style="font-size: 14px;">data_usage</span>
Activity Log
</h3>
<div id="activity-feed" class="bg-surface rounded-xl border border-surface-variant overflow-hidden max-h-[120px] overflow-y-auto">
<!-- items injected by JS -->
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════ -->
<!-- RIGHT (1/3): Live Monitor Panel -->
<!-- ═══════════════════════════════════════════ -->
<div class="bg-surface-container-lowest border border-surface-variant rounded-xl shadow-sm flex flex-col overflow-hidden">
<!-- Monitor Header -->
<div class="px-6 py-4 border-b border-surface-variant bg-surface flex items-center gap-2">
<div class="elapsed-dot"></div>
<h2 class="font-h3 text-h3 text-on-surface">Live Monitor</h2>
</div>
<div class="p-6 space-y-5 flex-1">
<!-- File Summary -->
<div class="flex items-center gap-3 p-3 rounded-xl bg-primary/5 border border-primary/10">
<span class="material-symbols-outlined text-primary" style="font-size: 28px;">description</span>
<div class="flex-1 min-w-0">
<p class="font-medium text-on-surface text-sm truncate">marketing_copy_v2.docx</p>
<p class="text-[11px] text-on-surface-variant">245 KB · Word Document</p>
</div>
</div>
<!-- Config Summary -->
<div class="space-y-3">
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">Source</span>
<span class="text-xs font-semibold text-on-surface bg-surface-container px-2 py-0.5 rounded" id="monitor-src">Auto-detect</span>
</div>
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">Target</span>
<span class="text-xs font-semibold text-on-surface bg-primary-fixed px-2 py-0.5 rounded text-on-primary-fixed" id="monitor-tgt">Français</span>
</div>
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">Engine</span>
<span class="text-xs font-semibold text-on-surface bg-surface-container px-2 py-0.5 rounded" id="monitor-engine">Google Traduction</span>
</div>
<div class="flex items-center justify-between py-2">
<span class="text-xs text-on-surface-variant">Started</span>
<span class="text-xs font-semibold text-on-surface" id="monitor-start-time"></span>
</div>
</div>
<!-- Quality Indicator -->
<div class="bg-surface rounded-xl p-3 border border-surface-variant">
<div class="flex items-center justify-between mb-2">
<span class="text-[10px] text-on-surface-variant uppercase tracking-wider font-semibold">Confidence</span>
<span id="stat-confidence" class="text-xs font-bold text-emerald-600"></span>
</div>
<div class="h-2 bg-surface-variant rounded-full overflow-hidden">
<div id="confidence-bar" class="h-full bg-gradient-to-r from-emerald-400 to-emerald-600 rounded-full transition-all duration-700" style="width: 0%"></div>
</div>
</div>
</div>
<!-- Cancel Button -->
<div class="p-6 pt-0">
<button class="w-full py-2.5 bg-white border-2 border-error/20 text-error rounded-lg font-label-md text-label-md flex items-center justify-center gap-2 hover:bg-error hover:text-white hover:border-error transition-all" onclick="cancelTranslation()">
<span class="material-symbols-outlined" style="font-size: 18px;">cancel</span>
Cancel Translation
</button>
</div>
</div>
</div>
<!-- Recent table (active translation row highlighted) -->
<div class="bg-surface-container-lowest border border-surface-variant rounded-xl shadow-sm overflow-hidden flex flex-col mt-6">
<div class="p-6 border-b border-surface-variant flex justify-between items-center bg-white">
<h2 class="font-h2 text-h2 text-on-surface flex items-center gap-2"><span class="material-symbols-outlined text-primary">history</span>Recent Translations</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead><tr class="bg-surface font-label-md text-label-md text-on-surface-variant border-b border-surface-variant"><th class="px-6 py-3 font-medium">File Name</th><th class="px-6 py-3 font-medium">Languages</th><th class="px-6 py-3 font-medium">Status</th><th class="px-6 py-3 font-medium">Date</th><th class="px-6 py-3 font-medium text-right">Action</th></tr></thead>
<tbody class="font-body-md text-body-md text-on-surface divide-y divide-surface-variant bg-white">
<tr class="hover:bg-surface-container-lowest transition-colors group bg-primary/[0.03]">
<td class="px-6 py-4"><div class="flex items-center gap-3"><span class="material-symbols-outlined text-primary">description</span><span class="font-medium text-primary">marketing_copy_v2.docx</span></div></td>
<td class="px-6 py-4"><div class="flex items-center gap-2 text-sm"><span class="px-2 py-0.5 bg-surface-container rounded text-on-surface-variant">Auto</span><span class="material-symbols-outlined text-outline" style="font-size: 16px;">arrow_right_alt</span><span class="px-2 py-0.5 bg-primary-fixed rounded text-on-primary-fixed">FR</span></div></td>
<td class="px-6 py-4"><div class="flex items-center gap-2 w-32"><div class="h-1.5 w-full bg-surface-variant rounded-full overflow-hidden"><div id="table-progress" class="h-full bg-primary rounded-full transition-all duration-700" style="width: 0%"></div></div><span id="table-pct" class="text-xs text-primary font-semibold">0%</span></div></td>
<td class="px-6 py-4 text-on-surface-variant text-sm">Now</td>
<td class="px-6 py-4 text-right"><button class="inline-flex items-center p-1.5 text-on-surface-variant hover:text-error transition-colors" title="Cancel" onclick="cancelTranslation()"><span class="material-symbols-outlined" style="font-size: 20px;">close</span></button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════ -->
<!-- STATE 3: Translation complete — REDESIGNED -->
<!-- ═══════════════════════════════════════════════════════════════ -->
<div id="state-complete" class="hidden">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Left: Success Card -->
<div class="lg:col-span-2 bg-surface-container-lowest border border-surface-variant rounded-xl shadow-sm overflow-hidden">
<!-- Success Header -->
<div class="bg-gradient-to-r from-emerald-500/10 to-emerald-600/5 border-b border-emerald-200/50 px-6 py-5 flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-emerald-500 flex items-center justify-center success-bounce shadow-lg shadow-emerald-500/20">
<span class="material-symbols-outlined text-white" style="font-size: 22px;">check</span>
</div>
<div>
<h2 class="font-h2 text-h2 text-on-surface leading-tight">Translation Complete</h2>
<p class="text-xs text-on-surface-variant mt-0.5">marketing_copy_v2.docx</p>
</div>
</div>
<div class="flex items-center gap-1.5 text-xs text-emerald-700 font-semibold bg-emerald-50 px-3 py-1.5 rounded-full border border-emerald-200/50">
<span class="material-symbols-outlined" style="font-size: 14px;">verified</span>
High Quality
</div>
</div>
<div class="p-6 space-y-6">
<!-- Result Stats -->
<div class="grid grid-cols-4 gap-3">
<div class="bg-emerald-50/50 rounded-xl p-3 text-center border border-emerald-100">
<span class="material-symbols-outlined text-emerald-600 mb-1" style="font-size: 20px;">segment</span>
<p id="result-segments" class="text-lg font-bold text-on-surface tabular-nums">142</p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Segments</p>
</div>
<div class="bg-emerald-50/50 rounded-xl p-3 text-center border border-emerald-100">
<span class="material-symbols-outlined text-emerald-600 mb-1" style="font-size: 20px;">text_snippet</span>
<p id="result-chars" class="text-lg font-bold text-on-surface tabular-nums">12,847</p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Characters</p>
</div>
<div class="bg-emerald-50/50 rounded-xl p-3 text-center border border-emerald-100">
<span class="material-symbols-outlined text-emerald-600 mb-1" style="font-size: 20px;">timer</span>
<p id="result-duration" class="text-lg font-bold text-on-surface tabular-nums">0:34</p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Duration</p>
</div>
<div class="bg-emerald-50/50 rounded-xl p-3 text-center border border-emerald-100">
<span class="material-symbols-outlined text-emerald-600 mb-1" style="font-size: 20px;">trending_up</span>
<p id="result-confidence" class="text-lg font-bold text-emerald-600 tabular-nums">96%</p>
<p class="text-[10px] text-on-surface-variant uppercase tracking-wider font-medium">Confidence</p>
</div>
</div>
<!-- Actions -->
<div class="flex items-center gap-3 justify-center py-2">
<button class="px-6 py-2.5 bg-primary text-on-primary rounded-lg font-label-md text-label-md flex items-center justify-center gap-2 hover:opacity-90 transition-opacity shadow-[0px_4px_6px_-1px_rgba(0,0,0,0.1)]">
<span class="material-symbols-outlined" style="font-size: 18px;">download</span>
Download Translated File
</button>
<button class="px-6 py-2.5 bg-white border border-surface-variant rounded-lg font-label-md text-label-md text-on-surface hover:bg-surface-container-low transition-colors shadow-sm flex items-center gap-2">
<span class="material-symbols-outlined" style="font-size: 18px;">visibility</span>
Preview
</button>
<button class="px-6 py-2.5 bg-white border border-surface-variant rounded-lg font-label-md text-label-md text-on-surface hover:bg-surface-container-low transition-colors shadow-sm flex items-center gap-2" onclick="resetState()">
<span class="material-symbols-outlined" style="font-size: 18px;">add</span>
New Translation
</button>
</div>
</div>
</div>
<!-- Right: Summary Panel -->
<div class="bg-surface-container-lowest border border-surface-variant rounded-xl p-6 shadow-sm flex flex-col">
<h2 class="font-h3 text-h3 text-on-surface mb-4 flex items-center gap-2">
<span class="material-symbols-outlined text-emerald-600" style="font-size: 20px;">summarize</span>
Summary
</h2>
<div class="space-y-3 flex-1">
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">Source</span>
<span class="text-xs font-semibold text-on-surface bg-surface-container px-2 py-0.5 rounded">Auto-detect</span>
</div>
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">Target</span>
<span class="text-xs font-semibold text-on-surface bg-primary-fixed px-2 py-0.5 rounded text-on-primary-fixed">Français</span>
</div>
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">Engine</span>
<span class="text-xs font-semibold text-on-surface bg-surface-container px-2 py-0.5 rounded">Google Traduction</span>
</div>
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">File Size</span>
<span class="text-xs font-semibold text-on-surface">245 KB</span>
</div>
<div class="flex items-center justify-between py-2 border-b border-surface-variant">
<span class="text-xs text-on-surface-variant">Pages</span>
<span class="text-xs font-semibold text-on-surface">12</span>
</div>
<div class="flex items-center justify-between py-2">
<span class="text-xs text-on-surface-variant">Completed</span>
<span class="text-xs font-semibold text-on-surface" id="complete-time">Just now</span>
</div>
</div>
<!-- Quality Bar -->
<div class="mt-4 bg-surface rounded-xl p-3 border border-surface-variant">
<div class="flex items-center justify-between mb-2">
<span class="text-[10px] text-on-surface-variant uppercase tracking-wider font-semibold">Translation Quality</span>
<span class="text-xs font-bold text-emerald-600">96%</span>
</div>
<div class="h-2 bg-surface-variant rounded-full overflow-hidden">
<div class="h-full bg-gradient-to-r from-emerald-400 to-emerald-600 rounded-full" style="width: 96%"></div>
</div>
</div>
</div>
</div>
<!-- Recent table with completed row -->
<div class="bg-surface-container-lowest border border-surface-variant rounded-xl shadow-sm overflow-hidden flex flex-col mt-6">
<div class="p-6 border-b border-surface-variant flex justify-between items-center bg-white">
<h2 class="font-h2 text-h2 text-on-surface flex items-center gap-2"><span class="material-symbols-outlined text-primary">history</span>Recent Translations</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead><tr class="bg-surface font-label-md text-label-md text-on-surface-variant border-b border-surface-variant"><th class="px-6 py-3 font-medium">File Name</th><th class="px-6 py-3 font-medium">Languages</th><th class="px-6 py-3 font-medium">Status</th><th class="px-6 py-3 font-medium">Date</th><th class="px-6 py-3 font-medium text-right">Action</th></tr></thead>
<tbody class="font-body-md text-body-md text-on-surface divide-y divide-surface-variant bg-white">
<tr class="hover:bg-surface-container-lowest transition-colors group bg-emerald-50/30">
<td class="px-6 py-4"><div class="flex items-center gap-3"><span class="material-symbols-outlined text-emerald-600">description</span><span class="font-medium text-on-surface">marketing_copy_v2.docx</span></div></td>
<td class="px-6 py-4"><div class="flex items-center gap-2 text-sm"><span class="px-2 py-0.5 bg-surface-container rounded text-on-surface-variant">Auto</span><span class="material-symbols-outlined text-outline" style="font-size: 16px;">arrow_right_alt</span><span class="px-2 py-0.5 bg-primary-fixed rounded text-on-primary-fixed">FR</span></div></td>
<td class="px-6 py-4"><span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-[#ecfdf5] text-[#065f46]"><span class="w-1.5 h-1.5 rounded-full bg-[#10b981]"></span>Completed</span></td>
<td class="px-6 py-4 text-on-surface-variant text-sm">Just now</td>
<td class="px-6 py-4 text-right"><button class="inline-flex items-center gap-1.5 px-3 py-1.5 bg-white border border-surface-variant rounded-md text-sm font-medium text-primary hover:bg-primary-fixed transition-colors"><span class="material-symbols-outlined" style="font-size: 16px;">download</span>Download</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- State switcher -->
<div class="fixed bottom-4 right-4 bg-white border border-slate-200 rounded-xl shadow-lg p-3 flex flex-col gap-1.5 z-50">
<p class="text-[10px] font-bold text-slate-400 uppercase tracking-wider px-2 mb-1">States</p>
<button class="state-btn active text-xs px-3 py-2 rounded-lg font-medium" onclick="showState('upload', this)">1. Upload</button>
<button class="state-btn text-xs px-3 py-2 rounded-lg bg-gray-100 text-gray-700 font-medium hover:bg-gray-200" onclick="startTranslation(); activateBtn(this)">2. Translating</button>
<button class="state-btn text-xs px-3 py-2 rounded-lg bg-gray-100 text-gray-700 font-medium hover:bg-gray-200" onclick="showComplete(); activateBtn(this)">3. Complete</button>
</div>
<script>
// ─── Combobox logic ───
function toggleDropdown(id) {
const dd = document.getElementById('dd-' + id);
const trigger = dd.previousElementSibling;
const isOpen = dd.classList.contains('open');
document.querySelectorAll('.combobox-dropdown').forEach(d => d.classList.remove('open'));
document.querySelectorAll('.combobox-trigger').forEach(t => t.classList.remove('active'));
if (!isOpen) {
dd.classList.add('open');
trigger.classList.add('active');
dd.querySelector('.combobox-search')?.focus();
}
}
function selectOption(id, label, value) {
const wrapper = document.querySelector(`[data-id="${id}"]`);
wrapper.querySelector('.selected-text').textContent = label;
wrapper.querySelectorAll('.combobox-option').forEach(opt => {
opt.classList.remove('selected');
opt.querySelector('.check').classList.add('hidden');
});
event.currentTarget.classList.add('selected');
event.currentTarget.querySelector('.check').classList.remove('hidden');
toggleDropdown(id);
}
function filterOptions(id, query) {
const dd = document.getElementById('dd-' + id);
const q = query.toLowerCase();
dd.querySelectorAll('.combobox-option').forEach(opt => {
const text = opt.querySelector('span').textContent.toLowerCase();
opt.style.display = text.includes(q) ? '' : 'none';
});
}
function swapLanguages() {
const src = document.querySelector('[data-id="source"] .selected-text');
const tgt = document.querySelector('[data-id="target"] .selected-text');
const tmp = src.textContent;
src.textContent = tgt.textContent;
tgt.textContent = tmp;
}
document.addEventListener('click', (e) => {
if (!e.target.closest('.combobox-wrapper')) {
document.querySelectorAll('.combobox-dropdown').forEach(d => d.classList.remove('open'));
document.querySelectorAll('.combobox-trigger').forEach(t => t.classList.remove('active'));
}
});
// ─── State management ───
function showState(state, btn) {
document.getElementById('state-upload').classList.add('hidden');
document.getElementById('state-translating').classList.add('hidden');
document.getElementById('state-complete').classList.add('hidden');
document.getElementById('state-' + state).classList.remove('hidden');
}
function activateBtn(btn) {
document.querySelectorAll('.state-btn').forEach(b => { b.classList.remove('active'); b.classList.add('bg-gray-100', 'text-gray-700'); b.classList.remove('bg-[#004ac6]', 'text-white'); });
btn.classList.add('active');
btn.classList.remove('bg-gray-100', 'text-gray-700');
}
function simulateUpload() {
document.getElementById('dropzone').classList.add('hidden');
document.getElementById('file-info').classList.remove('hidden');
}
function resetState() {
document.getElementById('dropzone').classList.remove('hidden');
document.getElementById('file-info').classList.add('hidden');
showState('upload', document.querySelector('.state-btn'));
activateBtn(document.querySelector('.state-btn'));
clearInterval(progressInterval);
clearInterval(elapsedInterval);
}
// ─── Pipeline Stepper Logic ───
function updateStepper(progress) {
const steps = document.querySelectorAll('#pipeline-stepper [data-step]');
const lines = document.querySelectorAll('#pipeline-stepper .step-line');
// Determine active step based on progress
let activeStep = 0;
if (progress >= 5) activeStep = 1; // Analyse
if (progress >= 25) activeStep = 2; // Traduction
if (progress >= 75) activeStep = 3; // Reconstruction
if (progress >= 95) activeStep = 4; // Finalisation
steps.forEach((step, i) => {
const circle = step.querySelector('.step-circle');
const label = step.querySelector('.step-label');
if (i < activeStep) {
// Completed
circle.className = 'step-circle bg-primary text-white shadow-md shadow-primary/20';
label.className = 'step-label text-[11px] font-medium text-primary';
} else if (i === activeStep) {
// Active — pulsing
circle.className = 'step-circle bg-primary text-white shadow-lg shadow-primary/30 ring-4 ring-primary/20';
label.className = 'step-label text-[11px] font-semibold text-primary';
} else {
// Pending
circle.className = 'step-circle bg-surface-variant text-on-surface-variant';
label.className = 'step-label text-[11px] font-medium text-on-surface-variant';
}
});
lines.forEach((line, i) => {
if (i < activeStep) {
line.className = 'step-line flex-1 bg-primary -mx-1 relative top-[-10px]';
} else {
line.className = 'step-line flex-1 bg-surface-variant -mx-1 relative top-[-10px]';
}
});
}
// ─── Activity Feed ───
function addActivity(icon, text) {
const feed = document.getElementById('activity-feed');
if (!feed) return;
const item = document.createElement('div');
item.className = 'activity-item flex items-center gap-2.5 px-3 py-2 border-b border-surface-variant last:border-0';
const time = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
item.innerHTML = `
<span class="material-symbols-outlined text-primary" style="font-size: 16px;">${icon}</span>
<span class="text-xs text-on-surface flex-1">${text}</span>
<span class="text-[10px] text-on-surface-variant tabular-nums">${time}</span>
`;
feed.insertBefore(item, feed.firstChild);
// Keep max 8 items
while (feed.children.length > 8) feed.removeChild(feed.lastChild);
}
// ─── Elapsed timer ───
let elapsedSeconds = 0;
let elapsedInterval;
function startElapsed() {
elapsedSeconds = 0;
clearInterval(elapsedInterval);
elapsedInterval = setInterval(() => {
elapsedSeconds++;
const m = Math.floor(elapsedSeconds / 60);
const s = elapsedSeconds % 60;
document.getElementById('stat-elapsed').textContent = `${m}:${s.toString().padStart(2, '0')}`;
}, 1000);
}
// ─── Translation simulation ───
let progressInterval;
function startTranslation() {
simulateUpload();
showState('translating');
startElapsed();
// Set start time in monitor
const now = new Date();
document.getElementById('monitor-start-time').textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
// Read config for monitor
const srcLang = document.querySelector('[data-id="source"] .selected-text')?.textContent || 'Auto-detect';
const tgtLang = document.querySelector('[data-id="target"] .selected-text')?.textContent || 'Français';
const engine = document.querySelector('[data-id="engine"] .selected-text')?.textContent || 'Google Traduction';
document.getElementById('monitor-src').textContent = srcLang;
document.getElementById('monitor-tgt').textContent = tgtLang;
document.getElementById('monitor-engine').textContent = engine;
let progress = 0;
const bar = document.getElementById('progress-bar');
const pct = document.getElementById('progress-pct');
const step = document.getElementById('progress-step');
const eta = document.getElementById('progress-eta');
const tbar = document.getElementById('table-progress');
const tpct = document.getElementById('table-pct');
const totalSegments = 142;
const totalChars = 12847;
// Clear activity feed
const feed = document.getElementById('activity-feed');
if (feed) feed.innerHTML = '';
addActivity('upload_file', 'Document uploaded successfully');
addActivity('search_insights', 'Starting document analysis...');
const steps = [
{ at: 0, text: 'Preparing document...', icon: 'upload_file' },
{ at: 5, text: 'Analyzing document structure...', icon: 'search_insights' },
{ at: 15, text: 'Extracting text segments...', icon: 'text_snippet' },
{ at: 25, text: 'Translating segments...', icon: 'translate' },
{ at: 50, text: 'Translating segments...', icon: 'translate' },
{ at: 75, text: 'Reconstructing document...', icon: 'build' },
{ at: 90, text: 'Applying formatting...', icon: 'format_paint' },
{ at: 95, text: 'Finalizing...', icon: 'task_alt' },
];
let lastActivityAt = -1;
clearInterval(progressInterval);
progressInterval = setInterval(() => {
progress += Math.random() * 3.5 + 0.8;
if (progress >= 100) {
progress = 100;
clearInterval(progressInterval);
clearInterval(elapsedInterval);
setTimeout(() => showComplete(), 500);
}
bar.style.width = progress + '%';
pct.textContent = Math.round(progress) + '%';
if (tbar) tbar.style.width = progress + '%';
if (tpct) tpct.textContent = Math.round(progress) + '%';
// Stepper
updateStepper(progress);
// Current step text
const current = steps.filter(s => progress >= s.at).pop();
if (current) step.textContent = current.text;
// Add activity log entries at thresholds
const activityThresholds = [
{ at: 5, icon: 'search_insights', text: 'Document analysis started' },
{ at: 15, icon: 'text_snippet', text: `Found ${totalSegments} translatable segments` },
{ at: 25, icon: 'translate', text: 'Translation engine connected' },
{ at: 40, icon: 'translate', text: `Translated ${Math.round(totalSegments*0.4)}/${totalSegments} segments` },
{ at: 55, icon: 'translate', text: `Translated ${Math.round(totalSegments*0.6)}/${totalSegments} segments` },
{ at: 70, icon: 'translate', text: `Translated ${Math.round(totalSegments*0.85)}/${totalSegments} segments` },
{ at: 80, icon: 'build', text: 'Document reconstruction started' },
{ at: 92, icon: 'format_paint', text: 'Applying original formatting' },
{ at: 97, icon: 'task_alt', text: 'Quality check passed' },
];
for (const t of activityThresholds) {
if (progress >= t.at && lastActivityAt < t.at) {
addActivity(t.icon, t.text);
lastActivityAt = t.at;
}
}
// Stats
const doneSeg = Math.round(totalSegments * progress / 100);
const doneChars = Math.round(totalChars * progress / 100);
document.getElementById('stat-segments').textContent = `${doneSeg}/${totalSegments}`;
document.getElementById('stat-chars').textContent = doneChars.toLocaleString();
// Speed (fake)
if (elapsedSeconds > 0) {
const speed = (doneSeg / (elapsedSeconds / 60)).toFixed(1);
document.getElementById('stat-speed').textContent = speed;
}
// Confidence (starts at 85, climbs to 96)
const conf = Math.min(96, 82 + progress * 0.14);
document.getElementById('stat-confidence').textContent = Math.round(conf) + '%';
document.getElementById('confidence-bar').style.width = conf + '%';
// ETA
const remaining = Math.max(0, Math.round((100 - progress) / 4));
eta.textContent = remaining > 0 ? `~${remaining}s remaining` : 'Almost done...';
}, 250);
activateBtn(document.querySelectorAll('.state-btn')[1]);
}
function cancelTranslation() {
clearInterval(progressInterval);
clearInterval(elapsedInterval);
resetState();
}
function showComplete() {
clearInterval(progressInterval);
clearInterval(elapsedInterval);
// Populate result stats
const m = Math.floor(elapsedSeconds / 60);
const s = elapsedSeconds % 60;
document.getElementById('result-duration').textContent = `${m}:${s.toString().padStart(2, '0')}`;
document.getElementById('result-confidence').textContent = '96%';
document.getElementById('result-segments').textContent = '142';
document.getElementById('result-chars').textContent = '12,847';
const now = new Date();
document.getElementById('complete-time').textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
showState('complete');
activateBtn(document.querySelectorAll('.state-btn')[2]);
}
</script>
</body></html>