Upload folder using huggingface_hub
Browse files
client/src/components/Refinity.tsx
CHANGED
|
@@ -86,10 +86,12 @@ const Refinity: React.FC = () => {
|
|
| 86 |
})();
|
| 87 |
}, [task?.id]);
|
| 88 |
|
|
|
|
| 89 |
const focusedIndex = React.useMemo(() => {
|
| 90 |
const idx = taskVersions.findIndex(v => v.id === currentVersionId);
|
| 91 |
-
|
| 92 |
-
|
|
|
|
| 93 |
|
| 94 |
const uploadDocx = async (file: File) => {
|
| 95 |
setUploading(true);
|
|
@@ -348,14 +350,21 @@ const Refinity: React.FC = () => {
|
|
| 348 |
</div>
|
| 349 |
</div>
|
| 350 |
|
| 351 |
-
<div className="relative overflow-
|
| 352 |
-
<div className="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
{taskVersions.map((v, idx) => {
|
| 354 |
const isCenter = idx === focusedIndex;
|
| 355 |
const sideOffset = Math.abs(idx - focusedIndex);
|
| 356 |
-
|
| 357 |
-
const
|
| 358 |
-
const
|
|
|
|
| 359 |
const snippet = (v.content || '').slice(0, 160) + ((v.content || '').length > 160 ? '…' : '');
|
| 360 |
return (
|
| 361 |
<div key={v.id} className="transition-transform duration-300"
|
|
@@ -374,8 +383,9 @@ const Refinity: React.FC = () => {
|
|
| 374 |
<button onClick={()=>selectManual(v.id)} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded-2xl text-white ring-1 ring-inset ring-white/50 backdrop-blur-md backdrop-brightness-110 backdrop-saturate-150 bg-indigo-600/70 active:translate-y-0.5 transition-all duration-200">
|
| 375 |
<div className="pointer-events-none absolute inset-0 rounded-2xl opacity-60 [background:linear-gradient(to_bottom,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%)]" />
|
| 376 |
<div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
|
| 377 |
-
<span className="relative z-10">
|
| 378 |
</button>
|
|
|
|
| 379 |
</div>
|
| 380 |
)}
|
| 381 |
</div>
|
|
@@ -440,13 +450,21 @@ const EditorPane: React.FC<{ source: string; initialTranslation: string; onBack:
|
|
| 440 |
const downloadWithTrackChanges = async ()=>{
|
| 441 |
try {
|
| 442 |
const base = ((api.defaults as any)?.baseURL as string || '').replace(/\/$/, '');
|
| 443 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
if (!resp.ok) throw new Error('Export failed');
|
| 445 |
const blob = await resp.blob();
|
| 446 |
const url = window.URL.createObjectURL(blob);
|
| 447 |
const a = document.createElement('a');
|
| 448 |
a.href = url;
|
| 449 |
-
a.download =
|
| 450 |
document.body.appendChild(a);
|
| 451 |
a.click();
|
| 452 |
a.remove();
|
|
@@ -516,7 +534,7 @@ const PreviewPane: React.FC<{ version: Version | null; onBack: ()=>void; onEdit:
|
|
| 516 |
</div>
|
| 517 |
</div>
|
| 518 |
<div className="mt-4 flex gap-3">
|
| 519 |
-
<button onClick={onEdit} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium rounded-2xl text-white ring-1 ring-inset ring-white/50 backdrop-blur-md backdrop-brightness-110 backdrop-saturate-150 bg-indigo-600/70 active:translate-y-0.5 transition-all duration-200">
|
| 520 |
<button onClick={onBack} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium rounded-2xl text-black ring-1 ring-inset ring-white/50 backdrop-blur-md bg-white/30 active:translate-y-0.5 transition-all duration-200">Back</button>
|
| 521 |
</div>
|
| 522 |
</div>
|
|
|
|
| 86 |
})();
|
| 87 |
}, [task?.id]);
|
| 88 |
|
| 89 |
+
const [flowIndex, setFlowIndex] = React.useState<number>(0);
|
| 90 |
const focusedIndex = React.useMemo(() => {
|
| 91 |
const idx = taskVersions.findIndex(v => v.id === currentVersionId);
|
| 92 |
+
if (idx >= 0) return idx;
|
| 93 |
+
return Math.min(Math.max(taskVersions.length - 1, 0), flowIndex);
|
| 94 |
+
}, [taskVersions, currentVersionId, flowIndex]);
|
| 95 |
|
| 96 |
const uploadDocx = async (file: File) => {
|
| 97 |
setUploading(true);
|
|
|
|
| 350 |
</div>
|
| 351 |
</div>
|
| 352 |
|
| 353 |
+
<div className="relative overflow-hidden py-10">
|
| 354 |
+
<div className="absolute left-2 top-1/2 -translate-y-1/2 z-10">
|
| 355 |
+
<button onClick={()=> setFlowIndex((i)=> Math.max(i-1, 0))} className="px-2 py-1 rounded-2xl bg-white/50 ring-1 ring-white/50 backdrop-blur-md text-sm">‹</button>
|
| 356 |
+
</div>
|
| 357 |
+
<div className="absolute right-2 top-1/2 -translate-y-1/2 z-10">
|
| 358 |
+
<button onClick={()=> setFlowIndex((i)=> Math.min(i+1, Math.max(taskVersions.length-1, 0)))} className="px-2 py-1 rounded-2xl bg-white/50 ring-1 ring-white/50 backdrop-blur-md text-sm">›</button>
|
| 359 |
+
</div>
|
| 360 |
+
<div className="flex items-center justify-center gap-8 px-16 transition-transform duration-300">
|
| 361 |
{taskVersions.map((v, idx) => {
|
| 362 |
const isCenter = idx === focusedIndex;
|
| 363 |
const sideOffset = Math.abs(idx - focusedIndex);
|
| 364 |
+
// Apple coverflow style: center slightly larger; others equal smaller, slight angle
|
| 365 |
+
const scale = isCenter ? 1.05 : 0.9;
|
| 366 |
+
const rotate = isCenter ? 0 : (idx < focusedIndex ? -10 : 10);
|
| 367 |
+
const opacity = isCenter ? 1 : 0.85;
|
| 368 |
const snippet = (v.content || '').slice(0, 160) + ((v.content || '').length > 160 ? '…' : '');
|
| 369 |
return (
|
| 370 |
<div key={v.id} className="transition-transform duration-300"
|
|
|
|
| 383 |
<button onClick={()=>selectManual(v.id)} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded-2xl text-white ring-1 ring-inset ring-white/50 backdrop-blur-md backdrop-brightness-110 backdrop-saturate-150 bg-indigo-600/70 active:translate-y-0.5 transition-all duration-200">
|
| 384 |
<div className="pointer-events-none absolute inset-0 rounded-2xl opacity-60 [background:linear-gradient(to_bottom,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%)]" />
|
| 385 |
<div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
|
| 386 |
+
<span className="relative z-10">Revise</span>
|
| 387 |
</button>
|
| 388 |
+
<button onClick={()=>{ setPreviewVersionId(v.id); setShowDiff(true); setStage('preview'); }} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded-2xl text-black ring-1 ring-inset ring-white/50 backdrop-blur-md bg-white/30 active:translate-y-0.5 transition-all duration-200">Compare</button>
|
| 389 |
</div>
|
| 390 |
)}
|
| 391 |
</div>
|
|
|
|
| 450 |
const downloadWithTrackChanges = async ()=>{
|
| 451 |
try {
|
| 452 |
const base = ((api.defaults as any)?.baseURL as string || '').replace(/\/$/, '');
|
| 453 |
+
const taskNameSafe = (task?.title || 'Task').replace(/[^\w\-\s]/g,'').replace(/\s+/g,'_');
|
| 454 |
+
const userNameSafe = (username || 'User').replace(/[^\w\-\s]/g,'').replace(/\s+/g,'_');
|
| 455 |
+
const currentNum = (String((initialTranslation||'').length) && 'v') + String((text||'').length ? '' : '');
|
| 456 |
+
const vNum = (()=>{
|
| 457 |
+
const target = (task?.id ? (versions.filter(v=>v.taskId===task.id).slice(-1)[0]?.versionNumber || 0) : 0) + 1;
|
| 458 |
+
return `v${target}`;
|
| 459 |
+
})();
|
| 460 |
+
const filename = `${taskNameSafe}_${userNameSafe}_${vNum}.docx`;
|
| 461 |
+
const resp = await fetch(`${base}/api/refinity/track-changes`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prev: initialTranslation || '', current: text || '', filename }) });
|
| 462 |
if (!resp.ok) throw new Error('Export failed');
|
| 463 |
const blob = await resp.blob();
|
| 464 |
const url = window.URL.createObjectURL(blob);
|
| 465 |
const a = document.createElement('a');
|
| 466 |
a.href = url;
|
| 467 |
+
a.download = filename;
|
| 468 |
document.body.appendChild(a);
|
| 469 |
a.click();
|
| 470 |
a.remove();
|
|
|
|
| 534 |
</div>
|
| 535 |
</div>
|
| 536 |
<div className="mt-4 flex gap-3">
|
| 537 |
+
<button onClick={onEdit} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium rounded-2xl text-white ring-1 ring-inset ring-white/50 backdrop-blur-md backdrop-brightness-110 backdrop-saturate-150 bg-indigo-600/70 active:translate-y-0.5 transition-all duration-200">Revise</button>
|
| 538 |
<button onClick={onBack} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium rounded-2xl text-black ring-1 ring-inset ring-white/50 backdrop-blur-md bg-white/30 active:translate-y-0.5 transition-all duration-200">Back</button>
|
| 539 |
</div>
|
| 540 |
</div>
|