linguabot commited on
Commit
2ff05f3
·
verified ·
1 Parent(s): 5d24ade

Upload folder using huggingface_hub

Browse files
client/public/rebuild-nonce.txt CHANGED
@@ -1 +1 @@
1
- Rebuild nonce: 2025-10-25T16:35:45Z
 
1
+ Rebuild nonce: 2025-10-25T16:45:12Z
client/src/pages/TutorialTasks.tsx CHANGED
@@ -1937,19 +1937,23 @@ const TutorialTasks: React.FC = () => {
1937
  </div>
1938
  </div>
1939
  ) : (
1940
- // Regular task layout - use grid for stability
1941
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start">
1942
  <div className="w-full flex justify-center">
1943
- {task.imageUrl.startsWith('data:') ? (
1944
  <div className="inline-block rounded-lg shadow-md overflow-hidden">
1945
  <img src={task.imageUrl} alt={task.imageAlt || 'Uploaded image'} className="w-full h-auto" style={{ height: '200px', width: 'auto', objectFit: 'contain' }} onError={(e) => { console.error('Image failed to load:', e); (e.currentTarget as HTMLImageElement).style.display = 'none'; }} />
1946
  </div>
1947
- ) : (
1948
  <div className="inline-block rounded-lg shadow-md bg-green-500 text-white p-6 text-center">
1949
  <div className="text-3xl mb-2">📷</div>
1950
  <div className="font-semibold">Image Uploaded</div>
1951
  <div className="text-sm opacity-75">{task.imageUrl}</div>
1952
  </div>
 
 
 
 
1953
  )}
1954
  </div>
1955
  <div className="w-full">
@@ -1957,40 +1961,6 @@ const TutorialTasks: React.FC = () => {
1957
  <h5 className="text-indigo-900 font-semibold mb-2">Source Text</h5>
1958
  <div className="text-blue-800 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{renderFormatted(task.content)}</div>
1959
  </div>
1960
- {localStorage.getItem('token') && (
1961
- <div className="bg-white rounded-lg p-4 border border-gray-200">
1962
- <h5 className="text-gray-900 font-semibold mb-2">Your Group's Translation</h5>
1963
- <div className="mb-2">
1964
- <label className="block text-xs font-medium text-gray-700 mb-1">Select Your Group</label>
1965
- <select
1966
- value={selectedGroups[task._id] || ''}
1967
- onChange={(e) => setSelectedGroups({ ...selectedGroups, [task._id]: parseInt(e.target.value) })}
1968
- className="w-40 px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 bg-white text-xs"
1969
- >
1970
- <option value="">Choose...</option>
1971
- {[1,2,3,4,5,6,7,8].map((g) => (<option key={g} value={g}>Group {g}</option>))}
1972
- </select>
1973
- </div>
1974
- <div className="flex items-center justify-end space-x-2 mb-2">
1975
- <button onClick={() => applyInlineFormat(`tutorial-translation-${task._id}`, translationText[task._id] || '', v => setTranslationText({ ...translationText, [task._id]: v }), '**')} className="px-2 py-1 text-xs bg-indigo-100 text-indigo-900 rounded">B</button>
1976
- <button onClick={() => applyInlineFormat(`tutorial-translation-${task._id}`, translationText[task._id] || '', v => setTranslationText({ ...translationText, [task._id]: v }), '*')} className="px-2 py-1 text-xs bg-indigo-100 text-indigo-900 rounded italic">I</button>
1977
- <button onClick={() => applyLinkFormat(`tutorial-translation-${task._id}`, translationText[task._id] || '', v => setTranslationText({ ...translationText, [task._id]: v }))} className="px-2 py-1 text-xs bg-indigo-100 text-indigo-900 rounded">Link</button>
1978
- </div>
1979
- <textarea
1980
- id={`tutorial-translation-${task._id}`}
1981
- value={translationText[task._id] || ''}
1982
- onInput={(e) => setTranslationText({ ...translationText, [task._id]: (e.target as HTMLTextAreaElement).value })}
1983
- onChange={(e) => setTranslationText({ ...translationText, [task._id]: e.target.value })}
1984
- className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 bg-white"
1985
- style={{ height: '150px' }}
1986
- rows={4}
1987
- placeholder="Enter your group's translation here..."
1988
- />
1989
- <div className="flex justify-end mt-2">
1990
- <button onClick={() => handleSubmitTranslation(task._id)} disabled={submitting[task._id]} className="btn-primary disabled:bg-gray-400 text-white px-4 py-2 rounded-lg text-sm">{submitting[task._id] ? 'Submitting...' : 'Submit Translation'}</button>
1991
- </div>
1992
- </div>
1993
- )}
1994
  </div>
1995
  </div>
1996
  )
@@ -2090,6 +2060,85 @@ const TutorialTasks: React.FC = () => {
2090
  </div>
2091
  )}
2092
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2093
 
2094
  {/* Show login message for visitors */}
2095
  {!localStorage.getItem('token') && (
 
1937
  </div>
1938
  </div>
1939
  ) : (
1940
+ // Regular task layout - use grid for stability like image-only layout
1941
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start">
1942
  <div className="w-full flex justify-center">
1943
+ {task.imageUrl && task.imageUrl.startsWith('data:') ? (
1944
  <div className="inline-block rounded-lg shadow-md overflow-hidden">
1945
  <img src={task.imageUrl} alt={task.imageAlt || 'Uploaded image'} className="w-full h-auto" style={{ height: '200px', width: 'auto', objectFit: 'contain' }} onError={(e) => { console.error('Image failed to load:', e); (e.currentTarget as HTMLImageElement).style.display = 'none'; }} />
1946
  </div>
1947
+ ) : task.imageUrl ? (
1948
  <div className="inline-block rounded-lg shadow-md bg-green-500 text-white p-6 text-center">
1949
  <div className="text-3xl mb-2">📷</div>
1950
  <div className="font-semibold">Image Uploaded</div>
1951
  <div className="text-sm opacity-75">{task.imageUrl}</div>
1952
  </div>
1953
+ ) : (
1954
+ <div className="w-full h-48 bg-gray-100 rounded-lg flex items-center justify-center">
1955
+ <div className="text-gray-500">No image</div>
1956
+ </div>
1957
  )}
1958
  </div>
1959
  <div className="w-full">
 
1961
  <h5 className="text-indigo-900 font-semibold mb-2">Source Text</h5>
1962
  <div className="text-blue-800 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{renderFormatted(task.content)}</div>
1963
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1964
  </div>
1965
  </div>
1966
  )
 
2060
  </div>
2061
  )}
2062
 
2063
+ {/* Translation Input (always show if user is logged in, but hide for image-only content) */}
2064
+ {localStorage.getItem('token') && task.content !== 'Image-based task' && (
2065
+ <div className="bg-white rounded-lg p-6 border border-gray-200 shadow-sm safari-stable-form">
2066
+ <div className="flex items-center space-x-3 mb-4">
2067
+ <div className="bg-gray-100 rounded-lg p-2">
2068
+ <DocumentTextIcon className="h-4 w-4 text-gray-600" />
2069
+ </div>
2070
+ <h4 className="text-gray-900 font-semibold text-lg">Group Translation</h4>
2071
+ </div>
2072
+
2073
+ {/* Group Selection */}
2074
+ <div className="mb-4">
2075
+ <label className="block text-sm font-medium text-gray-700 mb-2">
2076
+ Select Your Group *
2077
+ </label>
2078
+ <select
2079
+ value={selectedGroups[task._id] || ''}
2080
+ onChange={(e) => {
2081
+ const value = parseInt(e.target.value);
2082
+ setSelectedGroups({ ...selectedGroups, [task._id]: value });
2083
+ }}
2084
+ className="w-48 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"
2085
+ required
2086
+ >
2087
+ <option value="">Choose your group...</option>
2088
+ {[1, 2, 3, 4, 5, 6, 7, 8].map((group) => (
2089
+ <option key={group} value={group}>
2090
+ Group {group}
2091
+ </option>
2092
+ ))}
2093
+ </select>
2094
+ </div>
2095
+
2096
+ <div className="mb-4">
2097
+ <label className="block text-sm font-medium text-gray-700 mb-2">
2098
+ Your Group's Translation *
2099
+ </label>
2100
+ <div className="flex items-center justify-end space-x-2 mb-2">
2101
+ <button onClick={() => applyInlineFormat(`tutorial-translation-${task._id}`, translationText[task._id] || '', v => setTranslationText({ ...translationText, [task._id]: v }), '**')} className="px-2 py-1 text-xs bg-indigo-100 text-indigo-900 rounded">B</button>
2102
+ <button onClick={() => applyInlineFormat(`tutorial-translation-${task._id}`, translationText[task._id] || '', v => setTranslationText({ ...translationText, [task._id]: v }), '*')} className="px-2 py-1 text-xs bg-indigo-100 text-indigo-900 rounded italic">I</button>
2103
+ <button onClick={() => applyLinkFormat(`tutorial-translation-${task._id}`, translationText[task._id] || '', v => setTranslationText({ ...translationText, [task._id]: v }))} className="px-2 py-1 text-xs bg-indigo-100 text-indigo-900 rounded">Link</button>
2104
+ </div>
2105
+ <textarea
2106
+ id={`tutorial-translation-${task._id}`}
2107
+ value={translationText[task._id] || ''}
2108
+ onInput={(e) => {
2109
+ const value = (e.target as HTMLTextAreaElement).value;
2110
+ setTranslationText({ ...translationText, [task._id]: value });
2111
+ }}
2112
+ onChange={(e) => {
2113
+ const value = e.target.value;
2114
+ setTranslationText({ ...translationText, [task._id]: value });
2115
+ }}
2116
+ className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 bg-white"
2117
+ style={{ height: '150px' }}
2118
+ rows={4}
2119
+ placeholder="Enter your group's translation here..."
2120
+ />
2121
+ </div>
2122
+
2123
+ <button
2124
+ onClick={() => { (withPreservedScroll.current || ((fn)=>fn()))(() => {}); handleSubmitTranslation(task._id); }}
2125
+ disabled={submitting[task._id]}
2126
+ className="relative inline-flex items-center justify-center gap-2 px-4 py-2 rounded-2xl text-sm font-medium text-white ring-1 ring-inset ring-white/50 backdrop-blur-md backdrop-brightness-110 backdrop-saturate-150 shadow-[inset_0_1px_0_rgba(255,255,255,0.6),inset_0_-1px_0_rgba(0,0,0,0.12)] bg-sky-600/70 disabled:bg-gray-400"
2127
+ >
2128
+ {submitting[task._id] ? (
2129
+ <>
2130
+ <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
2131
+ Submitting...
2132
+ </>
2133
+ ) : (
2134
+ <>
2135
+ Submit Group Translation
2136
+ <ArrowRightIcon className="h-4 w-4 ml-2" />
2137
+ </>
2138
+ )}
2139
+ </button>
2140
+ </div>
2141
+ )}
2142
 
2143
  {/* Show login message for visitors */}
2144
  {!localStorage.getItem('token') && (