linguabot commited on
Commit
5d24ade
·
verified ·
1 Parent(s): 9fbc19d

Upload folder using huggingface_hub

Browse files
client/public/rebuild-nonce.txt CHANGED
@@ -1 +1 @@
1
- Rebuild nonce: 2025-10-25T16:25:33Z
 
1
+ Rebuild nonce: 2025-10-25T16:35:45Z
client/src/index.css CHANGED
@@ -26,6 +26,74 @@
26
  -webkit-backface-visibility: hidden;
27
  }
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
30
 
31
  @layer components {
 
26
  -webkit-backface-visibility: hidden;
27
  }
28
  }
29
+
30
+ /* Chrome-specific improvements */
31
+ html.is-chrome .safari-stable-form {
32
+ background: #ffffff;
33
+ border: 1px solid #e5e7eb;
34
+ border-radius: 12px;
35
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
36
+ }
37
+
38
+ html.is-chrome .safari-stable-form select {
39
+ background: #ffffff;
40
+ border: 1px solid #d1d5db;
41
+ border-radius: 8px;
42
+ padding: 8px 12px;
43
+ font-size: 14px;
44
+ font-weight: 500;
45
+ color: #374151;
46
+ transition: all 0.2s ease;
47
+ }
48
+
49
+ html.is-chrome .safari-stable-form select:focus {
50
+ outline: none;
51
+ border-color: #6366f1;
52
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
53
+ }
54
+
55
+ html.is-chrome .safari-stable-form textarea {
56
+ background: #ffffff;
57
+ border: 1px solid #d1d5db;
58
+ border-radius: 8px;
59
+ padding: 12px;
60
+ font-size: 14px;
61
+ font-weight: 400;
62
+ color: #374151;
63
+ transition: all 0.2s ease;
64
+ resize: none;
65
+ }
66
+
67
+ html.is-chrome .safari-stable-form textarea:focus {
68
+ outline: none;
69
+ border-color: #6366f1;
70
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
71
+ }
72
+
73
+ html.is-chrome .safari-stable-form button {
74
+ background: #6366f1;
75
+ color: #ffffff;
76
+ border: none;
77
+ border-radius: 8px;
78
+ padding: 8px 16px;
79
+ font-size: 14px;
80
+ font-weight: 500;
81
+ transition: all 0.2s ease;
82
+ cursor: pointer;
83
+ }
84
+
85
+ html.is-chrome .safari-stable-form button:hover {
86
+ background: #5856eb;
87
+ transform: translateY(-1px);
88
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
89
+ }
90
+
91
+ html.is-chrome .safari-stable-form button:disabled {
92
+ background: #9ca3af;
93
+ cursor: not-allowed;
94
+ transform: none;
95
+ box-shadow: none;
96
+ }
97
  }
98
 
99
  @layer components {
client/src/pages/TutorialTasks.tsx CHANGED
@@ -1937,9 +1937,9 @@ const TutorialTasks: React.FC = () => {
1937
  </div>
1938
  </div>
1939
  ) : (
1940
- // Regular task layout
1941
- <div className="flex flex-col md:flex-row gap-6 items-start">
1942
- <div className="w-full md:w-1/2 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'; }} />
@@ -1952,8 +1952,45 @@ const TutorialTasks: React.FC = () => {
1952
  </div>
1953
  )}
1954
  </div>
1955
- <div className="w-full md:w-1/2">
1956
- <div className="text-blue-800 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{renderFormatted(task.content)}</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1957
  </div>
1958
  </div>
1959
  )
@@ -2053,85 +2090,6 @@ const TutorialTasks: React.FC = () => {
2053
  </div>
2054
  )}
2055
 
2056
- {/* Translation Input (always show if user is logged in, but hide for image-only content) */}
2057
- {localStorage.getItem('token') && task.content !== 'Image-based task' && task.imageAlignment !== 'portrait-split' && (
2058
- <div className="bg-white rounded-lg p-6 border border-gray-200 shadow-sm safari-stable-form">
2059
- <div className="flex items-center space-x-3 mb-4">
2060
- <div className="bg-gray-100 rounded-lg p-2">
2061
- <DocumentTextIcon className="h-4 w-4 text-gray-600" />
2062
- </div>
2063
- <h4 className="text-gray-900 font-semibold text-lg">Group Translation</h4>
2064
- </div>
2065
-
2066
- {/* Group Selection */}
2067
- <div className="mb-4">
2068
- <label className="block text-sm font-medium text-gray-700 mb-2">
2069
- Select Your Group *
2070
- </label>
2071
- <select
2072
- value={selectedGroups[task._id] || ''}
2073
- onChange={(e) => {
2074
- const value = parseInt(e.target.value);
2075
- setSelectedGroups({ ...selectedGroups, [task._id]: value });
2076
- }}
2077
- 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"
2078
- required
2079
- >
2080
- <option value="">Choose your group...</option>
2081
- {[1, 2, 3, 4, 5, 6, 7, 8].map((group) => (
2082
- <option key={group} value={group}>
2083
- Group {group}
2084
- </option>
2085
- ))}
2086
- </select>
2087
- </div>
2088
-
2089
- <div className="mb-4">
2090
- <label className="block text-sm font-medium text-gray-700 mb-2">
2091
- Your Group's Translation *
2092
- </label>
2093
- <div className="flex items-center justify-end space-x-2 mb-2">
2094
- <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>
2095
- <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>
2096
- <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>
2097
- </div>
2098
- <textarea
2099
- id={`tutorial-translation-${task._id}`}
2100
- value={translationText[task._id] || ''}
2101
- onInput={(e) => {
2102
- const value = (e.target as HTMLTextAreaElement).value;
2103
- setTranslationText({ ...translationText, [task._id]: value });
2104
- }}
2105
- onChange={(e) => {
2106
- const value = e.target.value;
2107
- setTranslationText({ ...translationText, [task._id]: value });
2108
- }}
2109
- 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"
2110
- style={{ height: '150px' }}
2111
- rows={4}
2112
- placeholder="Enter your group's translation here..."
2113
- />
2114
- </div>
2115
-
2116
- <button
2117
- onClick={() => { (withPreservedScroll.current || ((fn)=>fn()))(() => {}); handleSubmitTranslation(task._id); }}
2118
- disabled={submitting[task._id]}
2119
- 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"
2120
- >
2121
- {submitting[task._id] ? (
2122
- <>
2123
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
2124
- Submitting...
2125
- </>
2126
- ) : (
2127
- <>
2128
- Submit Group Translation
2129
- <ArrowRightIcon className="h-4 w-4 ml-2" />
2130
- </>
2131
- )}
2132
- </button>
2133
- </div>
2134
- )}
2135
 
2136
  {/* Show login message for visitors */}
2137
  {!localStorage.getItem('token') && (
 
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'; }} />
 
1952
  </div>
1953
  )}
1954
  </div>
1955
+ <div className="w-full">
1956
+ <div className="bg-indigo-50 rounded-lg p-4 mb-4 border border-indigo-200">
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
  </div>
2091
  )}
2092
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2093
 
2094
  {/* Show login message for visitors */}
2095
  {!localStorage.getItem('token') && (