linguabot commited on
Commit
38d0bc3
·
verified ·
1 Parent(s): a049f87

Upload folder using huggingface_hub

Browse files
client/src/pages/TutorialTasks.tsx CHANGED
@@ -85,10 +85,12 @@ const TutorialTasks: React.FC = () => {
85
  try {
86
  const y = window.scrollY;
87
  fn();
88
- // Restore scroll position after DOM updates
89
  requestAnimationFrame(() => {
90
  requestAnimationFrame(() => {
91
- window.scrollTo(0, y);
 
 
92
  });
93
  });
94
  } catch {
 
85
  try {
86
  const y = window.scrollY;
87
  fn();
88
+ // Restore scroll position after DOM updates with multiple frames
89
  requestAnimationFrame(() => {
90
  requestAnimationFrame(() => {
91
+ requestAnimationFrame(() => {
92
+ window.scrollTo(0, y);
93
+ });
94
  });
95
  });
96
  } catch {
client/src/pages/WeeklyPractice.tsx CHANGED
@@ -1744,273 +1744,12 @@ const WeeklyPractice: React.FC = () => {
1744
  </div>
1745
  )}
1746
 
1747
- {/* Special Subtitling Interface for Week 2 (hidden from students when week is hidden) */}
1748
- {!isWeekTransitioning && selectedWeek === 2 && (isAdmin || !isWeekHidden) ? (
1749
- <div className="bg-white rounded-xl shadow p-6 mb-8">
1750
- <h3 className="text-lg font-semibold text-gray-900 mb-4">Week 2 Practice</h3>
1751
- {weeklyPracticeWeek?.translationBrief ? (
1752
- <div className="bg-ui-panel rounded-xl p-6 mb-6 border border-ui-border">
1753
- <h4 className="text-ui-text font-semibold text-base mb-2">Translation Brief</h4>
1754
- <div className="text-ui-text leading-relaxed whitespace-pre-wrap">{renderFormatted(weeklyPracticeWeek.translationBrief)}</div>
1755
- </div>
1756
- ) : null}
1757
- {((localStorage.getItem('viewMode')||'auto') !== 'student' && (JSON.parse(localStorage.getItem('user')||'{}').role === 'admin')) && (
1758
- <div className="mb-4">
1759
- <button onClick={() => setShowSubmissions(v=>!v)} className="px-3 py-1.5 text-sm rounded-md border border-gray-300">{showSubmissions ? 'Hide Subtitling UI' : 'Show Subtitling UI (Admin)'}</button>
1760
- </div>
1761
- )}
1762
- {weeklyPractice.length > 0 ? weeklyPractice.map((practice) => (
1763
- <div key={practice._id} className="bg-white rounded-xl shadow-lg border border-gray-100 p-8 hover:shadow-xl transition-shadow duration-300">
1764
- <div className="mb-6">
1765
- <div className="flex items-center justify-between mb-4">
1766
- <div className="flex items-center space-x-3">
1767
- <div className="bg-pink-100 rounded-full p-2">
1768
- <DocumentTextIcon className="h-5 w-5 text-pink-600" />
1769
- </div>
1770
- <div>
1771
- <h3 className="text-lg font-semibold text-gray-900">Source Text #{weeklyPractice.indexOf(practice) + 1}</h3>
1772
- </div>
1773
- </div>
1774
- {((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
1775
- <div className="flex items-center space-x-2">
1776
- {editingPractice === practice._id ? (
1777
- <>
1778
- <button
1779
- onClick={savePractice}
1780
- disabled={saving}
1781
- className="bg-green-100 hover:bg-green-200 text-green-700 px-3 py-1 rounded-lg transition-colors duration-200"
1782
- >
1783
- {saving ? (
1784
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-green-600"></div>
1785
- ) : (
1786
- <CheckIcon className="h-4 w-4" />
1787
- )}
1788
- </button>
1789
- <button
1790
- onClick={cancelEditing}
1791
- className="bg-red-100 hover:bg-red-200 text-red-700 px-3 py-1 rounded-lg transition-colors duration-200"
1792
- >
1793
- <XMarkIcon className="h-4 w-4" />
1794
- </button>
1795
- </>
1796
- ) : (
1797
- <>
1798
- <button
1799
- onClick={() => startEditing(practice)}
1800
- className="bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-lg transition-colors duration-200"
1801
- >
1802
- <PencilIcon className="h-4 w-4" />
1803
- </button>
1804
- <button
1805
- onClick={() => deletePractice(practice._id)}
1806
- className="bg-red-100 hover:bg-red-200 text-red-700 px-3 py-1 rounded-lg transition-colors duration-200"
1807
- >
1808
- <TrashIcon className="h-4 w-4" />
1809
- </button>
1810
- </>
1811
- )}
1812
- </div>
1813
- )}
1814
- </div>
1815
-
1816
- {/* Content - Gradient underlay + glass overlay */}
1817
- <div className="relative rounded-xl mb-6 p-0 border border-pink-200/60">
1818
- <div className="absolute inset-0 rounded-xl bg-gradient-to-r from-pink-200/45 via-rose-200/40 to-pink-300/45" />
1819
- <div className="relative rounded-xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)] p-6">
1820
- <div className="pointer-events-none absolute inset-0 rounded-xl opacity-50 [background:linear-gradient(to_bottom,rgba(255,255,255,0.3),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.28),rgba(255,255,255,0)_28%)]" />
1821
- <div className="pointer-events-none absolute inset-0 rounded-xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-45" />
1822
- <div className="pointer-events-none absolute inset-0 rounded-xl" style={{ background: 'radial-gradient(120% 120% at 50% 55%, rgba(0,0,0,0.03), rgba(0,0,0,0) 60%)' }} />
1823
- <div className="pointer-events-none absolute inset-0 rounded-xl bg-pink-500/10 mix-blend-overlay opacity-25" />
1824
- {editingPractice === practice._id ? (
1825
- <div className="space-y-4">
1826
- <textarea
1827
- value={editForm.content}
1828
- onChange={(e) => setEditForm({...editForm, content: e.target.value})}
1829
- className="w-full px-4 py-3 border border-orange-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500 focus:border-orange-500 bg-white"
1830
- rows={5}
1831
- placeholder="Enter source text..."
1832
- />
1833
- {selectedWeek >= 2 && (
1834
- <div className="space-y-3">
1835
- <div>
1836
- <label className="block text-sm font-medium text-orange-700 mb-1">Image URL</label>
1837
- <input
1838
- type="text"
1839
- value={editForm.imageUrl}
1840
- onChange={(e) => setEditForm({...editForm, imageUrl: e.target.value})}
1841
- className="w-full px-3 py-2 border border-orange-300 rounded-md focus:outline-none focus:ring-2 focus:ring-orange-500"
1842
- placeholder="Enter image URL..."
1843
- />
1844
- </div>
1845
- <div>
1846
- <label className="block text-sm font-medium text-orange-700 mb-1">Image Alt Text</label>
1847
- <input
1848
- type="text"
1849
- value={editForm.imageAlt}
1850
- onChange={(e) => setEditForm({...editForm, imageAlt: e.target.value})}
1851
- className="w-full px-3 py-2 border border-orange-300 rounded-md focus:outline-none focus:ring-2 focus:ring-orange-500"
1852
- placeholder="Enter alt text for accessibility..."
1853
- />
1854
- </div>
1855
- <div>
1856
- <label className="block text-sm font-medium text-orange-700 mb-1">Upload Local Image</label>
1857
- <input
1858
- type="file"
1859
- accept="image/*"
1860
- onChange={async (e) => {
1861
- const file = e.target.files?.[0];
1862
- if (file) {
1863
- try {
1864
- const imageUrl = await handleFileUpload(file);
1865
- setEditForm({ ...editForm, imageUrl });
1866
- } catch (error) {
1867
- console.error('Error uploading file:', error);
1868
- }
1869
- }
1870
- }}
1871
- className="w-full px-3 py-2 border border-orange-300 rounded-md focus:outline-none focus:ring-2 focus:ring-orange-500"
1872
- />
1873
- {uploading && (
1874
- <div className="mt-2 text-sm text-orange-600">
1875
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-orange-600 inline-block mr-2"></div>
1876
- Uploading...
1877
- </div>
1878
- )}
1879
- </div>
1880
- </div>
1881
- )}
1882
- </div>
1883
- ) : (
1884
- <div>
1885
- {practice.imageUrl ? (
1886
- selectedWeek >= 4 && practice.imageAlignment === 'portrait-split' ? (
1887
- // Portrait split layout
1888
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start">
1889
- <div className="w-full flex justify-center">
1890
- <div className="inline-block rounded-lg shadow-md overflow-hidden">
1891
- <img src={practice.imageUrl} alt={practice.imageAlt || 'Uploaded image'} className="w-full h-auto" style={{ maxHeight: '520px', objectFit: 'contain' }} />
1892
- </div>
1893
- </div>
1894
- <div className="w-full">
1895
- <div className="mb-4 text-ui-text leading-relaxed text-lg font-source-text whitespace-pre-wrap">{practice.content}</div>
1896
- {localStorage.getItem('token') && (
1897
- <div className="relative rounded-xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)] p-4">
1898
- <div className="pointer-events-none absolute inset-0 rounded-xl opacity-50 [background:linear-gradient(to_bottom,rgba(255,255,255,0.3),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.28),rgba(255,255,255,0)_28%)]" />
1899
- <div className="pointer-events-none absolute inset-0 rounded-xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-45" />
1900
- <h5 className="relative z-10 text-ui-text font-semibold mb-2">Your Translation</h5>
1901
- <div className="relative z-10 flex items-center justify-end space-x-2 mb-2">
1902
- <button onClick={() => applyInlineFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }), '**')} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded">B</button>
1903
- <button onClick={() => applyInlineFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }), '*')} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded italic">I</button>
1904
- <button onClick={() => applyLinkFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }))} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded">Link</button>
1905
- </div>
1906
- <textarea id={`weekly-translation-${practice._id}`} value={translationText[practice._id] || ''} onChange={(e) => setTranslationText({ ...translationText, [practice._id]: e.target.value })} className="relative z-10 w-full px-4 py-3 border border-ui-border rounded-lg focus:outline-none focus:ring-2 focus:ring-pink-500 focus:border-pink-500 bg-white" rows={4} placeholder="Enter your translation here..." />
1907
- <div className="relative z-10 flex justify-end mt-2">
1908
- <button onClick={() => handleSubmitTranslation(practice._id)} disabled={submitting[practice._id]} 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-pink-600/70 disabled:bg-gray-400 active:translate-y-0.5 active:shadow-[inset_0_0.5px_0_rgba(255,255,255,0.6),inset_0_-1px_0_rgba(0,0,0,0.12)] transition-all duration-200">
1909
- <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%)]" />
1910
- <div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
1911
- {submitting[practice._id] ? (
1912
- <>
1913
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
1914
- Submitting...
1915
- </>
1916
- ) : (
1917
- <>
1918
- <CheckIcon className="h-4 w-4" />
1919
- Submit Translation
1920
- </>
1921
- )}
1922
- </button>
1923
- </div>
1924
- </div>
1925
- )}
1926
- </div>
1927
- </div>
1928
- ) : (
1929
- // Regular image layout
1930
- <div className="space-y-4">
1931
- <div className="flex justify-center">
1932
- <div className="inline-block rounded-lg shadow-md overflow-hidden">
1933
- <img src={practice.imageUrl} alt={practice.imageAlt || 'Uploaded image'} className="w-full h-auto" style={{ maxHeight: '400px', objectFit: 'contain' }} />
1934
- </div>
1935
- </div>
1936
- <div className="text-ui-text leading-relaxed text-lg font-source-text whitespace-pre-wrap">{practice.content}</div>
1937
- {localStorage.getItem('token') && (
1938
- <div className="relative rounded-xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)] p-4">
1939
- <div className="pointer-events-none absolute inset-0 rounded-xl opacity-50 [background:linear-gradient(to_bottom,rgba(255,255,255,0.3),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.28),rgba(255,255,255,0)_28%)]" />
1940
- <div className="pointer-events-none absolute inset-0 rounded-xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-45" />
1941
- <h5 className="relative z-10 text-ui-text font-semibold mb-2">Your Translation</h5>
1942
- <div className="relative z-10 flex items-center justify-end space-x-2 mb-2">
1943
- <button onClick={() => applyInlineFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }), '**')} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded">B</button>
1944
- <button onClick={() => applyInlineFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }), '*')} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded italic">I</button>
1945
- <button onClick={() => applyLinkFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }))} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded">Link</button>
1946
- </div>
1947
- <textarea id={`weekly-translation-${practice._id}`} value={translationText[practice._id] || ''} onChange={(e) => setTranslationText({ ...translationText, [practice._id]: e.target.value })} className="relative z-10 w-full px-4 py-3 border border-ui-border rounded-lg focus:outline-none focus:ring-2 focus:ring-pink-500 focus:border-pink-500 bg-white" rows={4} placeholder="Enter your translation here..." />
1948
- <div className="relative z-10 flex justify-end mt-2">
1949
- <button onClick={() => handleSubmitTranslation(practice._id)} disabled={submitting[practice._id]} 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-pink-600/70 disabled:bg-gray-400 active:translate-y-0.5 active:shadow-[inset_0_0.5px_0_rgba(255,255,255,0.6),inset_0_-1px_0_rgba(0,0,0,0.12)] transition-all duration-200">
1950
- <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%)]" />
1951
- <div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
1952
- {submitting[practice._id] ? (
1953
- <>
1954
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
1955
- Submitting...
1956
- </>
1957
- ) : (
1958
- <>
1959
- <CheckIcon className="h-4 w-4" />
1960
- Submit Translation
1961
- </>
1962
- )}
1963
- </button>
1964
- </div>
1965
- </div>
1966
- )}
1967
- </div>
1968
- )
1969
- ) : (
1970
- // Text-only layout
1971
- <div className="mb-4 text-ui-text leading-relaxed text-lg font-source-text whitespace-pre-wrap">{practice.content}</div>
1972
- )}
1973
- {localStorage.getItem('token') && !practice.imageUrl && (
1974
- <div className="relative rounded-xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)] p-4">
1975
- <div className="pointer-events-none absolute inset-0 rounded-xl opacity-50 [background:linear-gradient(to_bottom,rgba(255,255,255,0.3),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.28),rgba(255,255,255,0)_28%)]" />
1976
- <div className="pointer-events-none absolute inset-0 rounded-xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-45" />
1977
- <h5 className="relative z-10 text-ui-text font-semibold mb-2">Your Translation</h5>
1978
- <div className="relative z-10 flex items-center justify-end space-x-2 mb-2">
1979
- <button onClick={() => applyInlineFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }), '**')} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded">B</button>
1980
- <button onClick={() => applyInlineFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }), '*')} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded italic">I</button>
1981
- <button onClick={() => applyLinkFormat(`weekly-translation-${practice._id}`, translationText[practice._id] || '', v => setTranslationText({ ...translationText, [practice._id]: v }))} className="px-2 py-1 text-xs bg-white/40 text-ui-text rounded">Link</button>
1982
- </div>
1983
- <textarea id={`weekly-translation-${practice._id}`} value={translationText[practice._id] || ''} onChange={(e) => setTranslationText({ ...translationText, [practice._id]: e.target.value })} className="relative z-10 w-full px-4 py-3 border border-ui-border rounded-lg focus:outline-none focus:ring-2 focus:ring-pink-500 focus:border-pink-500 bg-white" rows={4} placeholder="Enter your translation here..." />
1984
- <div className="relative z-10 flex justify-end mt-2">
1985
- <button onClick={() => handleSubmitTranslation(practice._id)} disabled={submitting[practice._id]} 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-pink-600/70 disabled:bg-gray-400 active:translate-y-0.5 active:shadow-[inset_0_0.5px_0_rgba(255,255,255,0.6),inset_0_-1px_0_rgba(0,0,0,0.12)] transition-all duration-200">
1986
- <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%)]" />
1987
- <div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
1988
- {submitting[practice._id] ? (
1989
- <>
1990
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
1991
- Submitting...
1992
- </>
1993
- ) : (
1994
- <>
1995
- <CheckIcon className="h-4 w-4" />
1996
- Submit Translation
1997
- </>
1998
- )}
1999
- </button>
2000
- </div>
2001
- </div>
2002
- )}
2003
- </div>
2004
- )}
2005
- </div>
2006
- </div>
2007
- </div>
2008
- </div>
2009
- )) : (
2010
- <div className="text-gray-600">No practice items for Week 2 yet.</div>
2011
- )}
2012
- </div>
2013
- ) : null}
2014
  {((localStorage.getItem('viewMode')||'auto') !== 'student' && (JSON.parse(localStorage.getItem('user')||'{}').role === 'admin') && showSubmissions) && (
2015
  <>
2016
  <div className="bg-white rounded-xl shadow-lg border border-gray-100 p-6">
@@ -2212,6 +1951,16 @@ const WeeklyPractice: React.FC = () => {
2212
  </div>
2213
  ) : (
2214
  <div className="space-y-6">
 
 
 
 
 
 
 
 
 
 
2215
  {/* Add Practice Button for Admin */}
2216
  {(() => {
2217
  const user = JSON.parse(localStorage.getItem('user') || '{}');
 
1744
  </div>
1745
  )}
1746
 
1747
+ {/* Subtitling UI for Week 2 (admin only) */}
1748
+ {!isWeekTransitioning && selectedWeek === 2 && (isAdmin || !isWeekHidden) && showSubmissions && (
1749
+ <div className="mb-8">
1750
+ <div className="mb-4">
1751
+ <button onClick={() => setShowSubmissions(false)} className="px-3 py-1.5 text-sm rounded-md border border-gray-300">Hide Subtitling UI</button>
1752
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1753
  {((localStorage.getItem('viewMode')||'auto') !== 'student' && (JSON.parse(localStorage.getItem('user')||'{}').role === 'admin') && showSubmissions) && (
1754
  <>
1755
  <div className="bg-white rounded-xl shadow-lg border border-gray-100 p-6">
 
1951
  </div>
1952
  ) : (
1953
  <div className="space-y-6">
1954
+ {/* Show Subtitling UI Button for Week 2 Admin */}
1955
+ {selectedWeek === 2 && (() => {
1956
+ const user = JSON.parse(localStorage.getItem('user') || '{}');
1957
+ const viewMode = (localStorage.getItem('viewMode') || 'auto');
1958
+ return viewMode === 'student' ? false : user.role === 'admin';
1959
+ })() && (
1960
+ <div className="mb-4">
1961
+ <button onClick={() => setShowSubmissions(v=>!v)} className="px-3 py-1.5 text-sm rounded-md border border-gray-300">{showSubmissions ? 'Hide Subtitling UI' : 'Show Subtitling UI (Admin)'}</button>
1962
+ </div>
1963
+ )}
1964
  {/* Add Practice Button for Admin */}
1965
  {(() => {
1966
  const user = JSON.parse(localStorage.getItem('user') || '{}');