Upload folder using huggingface_hub
Browse files
client/src/components/Refinity.tsx
CHANGED
|
@@ -825,6 +825,8 @@ const Refinity: React.FC = () => {
|
|
| 825 |
taskTitle={task?.title || 'Task'}
|
| 826 |
username={username}
|
| 827 |
nextVersionNumber={((versions.filter(v=>v.taskId===(task?.id||'')).slice(-1)[0]?.versionNumber) || 0) + 1}
|
|
|
|
|
|
|
| 828 |
/>
|
| 829 |
)}
|
| 830 |
</div>
|
|
@@ -832,7 +834,7 @@ const Refinity: React.FC = () => {
|
|
| 832 |
);
|
| 833 |
};
|
| 834 |
|
| 835 |
-
const EditorPane: React.FC<{ source: string; initialTranslation: string; onBack: ()=>void; onSave: (text: string)=>void; taskTitle: string; username: string; nextVersionNumber: number }>=({ source, initialTranslation, onBack, onSave, taskTitle, username, nextVersionNumber })=>{
|
| 836 |
const [text, setText] = React.useState<string>(initialTranslation);
|
| 837 |
const [saving, setSaving] = React.useState(false);
|
| 838 |
const [diffHtml, setDiffHtml] = React.useState<string>('');
|
|
@@ -842,6 +844,9 @@ const EditorPane: React.FC<{ source: string; initialTranslation: string; onBack:
|
|
| 842 |
const revBtnRef = React.useRef<HTMLButtonElement | null>(null);
|
| 843 |
const sourceRef = React.useRef<HTMLDivElement>(null);
|
| 844 |
const [textareaHeight, setTextareaHeight] = React.useState('420px');
|
|
|
|
|
|
|
|
|
|
| 845 |
|
| 846 |
React.useEffect(() => {
|
| 847 |
if (sourceRef.current) {
|
|
@@ -906,7 +911,12 @@ const EditorPane: React.FC<{ source: string; initialTranslation: string; onBack:
|
|
| 906 |
</div>
|
| 907 |
</div>
|
| 908 |
<div className="w-1/2">
|
| 909 |
-
<div className="mb-2 text-gray-700 text-sm">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 910 |
<textarea
|
| 911 |
value={text}
|
| 912 |
onChange={(e)=>setText(e.target.value)}
|
|
@@ -922,8 +932,25 @@ const EditorPane: React.FC<{ source: string; initialTranslation: string; onBack:
|
|
| 922 |
<div className="relative inline-block align-top">
|
| 923 |
<button ref={revBtnRef} onClick={async (e)=>{ e.preventDefault(); e.stopPropagation(); try { const base=((api.defaults as any)?.baseURL as string||'').replace(/\/$/,''); const filename=`${(taskTitle||'Task').replace(/[^\w\-\s]/g,'').replace(/\s+/g,'_')}_${(username||'User').replace(/[^\w\-\s]/g,'').replace(/\s+/g,'_')}.docx`; const body={ current: text||'', filename }; const resp=await fetch(`${base}/api/refinity/export-plain`,{ method:'POST', headers:{ 'Content-Type':'application/json' }, body: JSON.stringify(body) }); if(!resp.ok) throw new Error('Export failed'); const blob=await resp.blob(); const url=window.URL.createObjectURL(blob); const link=document.createElement('a'); link.href=url; link.download=filename; document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url);} catch {} }} 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">Download</button>
|
| 924 |
</div>
|
|
|
|
| 925 |
<button onClick={onBack} className="ml-auto 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>
|
| 926 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 927 |
{showDiff && (
|
| 928 |
<div className="mt-6 relative rounded-xl">
|
| 929 |
<div className="absolute inset-0 rounded-xl bg-gradient-to-r from-indigo-200/45 via-indigo-100/40 to-indigo-300/45" />
|
|
|
|
| 825 |
taskTitle={task?.title || 'Task'}
|
| 826 |
username={username}
|
| 827 |
nextVersionNumber={((versions.filter(v=>v.taskId===(task?.id||'')).slice(-1)[0]?.versionNumber) || 0) + 1}
|
| 828 |
+
isFullscreen={isFullscreen}
|
| 829 |
+
onToggleFullscreen={()=>setIsFullscreen(v=>!v)}
|
| 830 |
/>
|
| 831 |
)}
|
| 832 |
</div>
|
|
|
|
| 834 |
);
|
| 835 |
};
|
| 836 |
|
| 837 |
+
const EditorPane: React.FC<{ source: string; initialTranslation: string; onBack: ()=>void; onSave: (text: string)=>void; taskTitle: string; username: string; nextVersionNumber: number; isFullscreen: boolean; onToggleFullscreen: ()=>void }>=({ source, initialTranslation, onBack, onSave, taskTitle, username, nextVersionNumber, isFullscreen, onToggleFullscreen })=>{
|
| 838 |
const [text, setText] = React.useState<string>(initialTranslation);
|
| 839 |
const [saving, setSaving] = React.useState(false);
|
| 840 |
const [diffHtml, setDiffHtml] = React.useState<string>('');
|
|
|
|
| 844 |
const revBtnRef = React.useRef<HTMLButtonElement | null>(null);
|
| 845 |
const sourceRef = React.useRef<HTMLDivElement>(null);
|
| 846 |
const [textareaHeight, setTextareaHeight] = React.useState('420px');
|
| 847 |
+
const [commentsOpen, setCommentsOpen] = React.useState(false);
|
| 848 |
+
const [newComment, setNewComment] = React.useState('');
|
| 849 |
+
const [comments, setComments] = React.useState<Array<{ id: string; text: string; ts: number }>>([]);
|
| 850 |
|
| 851 |
React.useEffect(() => {
|
| 852 |
if (sourceRef.current) {
|
|
|
|
| 911 |
</div>
|
| 912 |
</div>
|
| 913 |
<div className="w-1/2">
|
| 914 |
+
<div className="mb-2 text-gray-700 text-sm flex items-center justify-between">
|
| 915 |
+
<span>Translation</span>
|
| 916 |
+
<button onClick={onToggleFullscreen} className="inline-flex items-center px-2 py-1 text-xs rounded-xl bg-white/60 ring-1 ring-gray-200 text-gray-800 hover:bg-white">
|
| 917 |
+
{isFullscreen ? 'Windowed' : 'Full Screen'}
|
| 918 |
+
</button>
|
| 919 |
+
</div>
|
| 920 |
<textarea
|
| 921 |
value={text}
|
| 922 |
onChange={(e)=>setText(e.target.value)}
|
|
|
|
| 932 |
<div className="relative inline-block align-top">
|
| 933 |
<button ref={revBtnRef} onClick={async (e)=>{ e.preventDefault(); e.stopPropagation(); try { const base=((api.defaults as any)?.baseURL as string||'').replace(/\/$/,''); const filename=`${(taskTitle||'Task').replace(/[^\w\-\s]/g,'').replace(/\s+/g,'_')}_${(username||'User').replace(/[^\w\-\s]/g,'').replace(/\s+/g,'_')}.docx`; const body={ current: text||'', filename }; const resp=await fetch(`${base}/api/refinity/export-plain`,{ method:'POST', headers:{ 'Content-Type':'application/json' }, body: JSON.stringify(body) }); if(!resp.ok) throw new Error('Export failed'); const blob=await resp.blob(); const url=window.URL.createObjectURL(blob); const link=document.createElement('a'); link.href=url; link.download=filename; document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url);} catch {} }} 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">Download</button>
|
| 934 |
</div>
|
| 935 |
+
<button onClick={()=>setCommentsOpen(o=>!o)} className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-3 py-2 text-xs font-medium rounded-2xl text-black ring-1 ring-inset ring-white/50 backdrop-blur-md bg-white/30 hover:bg-white/50 transition-all duration-200">Comments</button>
|
| 936 |
<button onClick={onBack} className="ml-auto 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>
|
| 937 |
</div>
|
| 938 |
+
{commentsOpen && (
|
| 939 |
+
<div className="mt-3 rounded-xl border border-gray-200 bg-white/60 p-3">
|
| 940 |
+
<div className="text-sm text-gray-800 mb-2">Add a brief comment (optional)</div>
|
| 941 |
+
<div className="flex gap-2">
|
| 942 |
+
<input value={newComment} onChange={(e)=>setNewComment(e.target.value)} className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 bg-white text-sm" placeholder="Your comment…" />
|
| 943 |
+
<button onClick={()=>{ const t=newComment.trim(); if(t){ setComments(prev=>[{ id: String(Date.now()), text: t, ts: Date.now() }, ...prev]); setNewComment(''); } }} className="px-3 py-2 text-xs rounded-xl bg-indigo-600/70 text-white hover:bg-indigo-700">Add</button>
|
| 944 |
+
</div>
|
| 945 |
+
{comments.length>0 && (
|
| 946 |
+
<div className="mt-3 space-y-2 max-h-40 overflow-auto">
|
| 947 |
+
{comments.map(c=>(
|
| 948 |
+
<div key={c.id} className="text-xs text-gray-700 bg-white rounded-lg border border-gray-200 p-2">{c.text}</div>
|
| 949 |
+
))}
|
| 950 |
+
</div>
|
| 951 |
+
)}
|
| 952 |
+
</div>
|
| 953 |
+
)}
|
| 954 |
{showDiff && (
|
| 955 |
<div className="mt-6 relative rounded-xl">
|
| 956 |
<div className="absolute inset-0 rounded-xl bg-gradient-to-r from-indigo-200/45 via-indigo-100/40 to-indigo-300/45" />
|