Upload folder using huggingface_hub
Browse files
client/src/pages/TutorialTasks.tsx
CHANGED
|
@@ -73,6 +73,23 @@ const TutorialTasks: React.FC = () => {
|
|
| 73 |
const cardRefs = useRef<{[key: string]: HTMLDivElement | null}>({});
|
| 74 |
const [listLockedHeight, setListLockedHeight] = useState<number | null>(null);
|
| 75 |
const listRef = useRef<HTMLDivElement | null>(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
// Move a task up or down by normalizing positions for the current visible list (weeks 4–6 only)
|
| 78 |
const moveTask = async (taskId: string, direction: 'up' | 'down') => {
|
|
@@ -1665,7 +1682,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 1665 |
</div>
|
| 1666 |
)}
|
| 1667 |
|
| 1668 |
-
<div ref={listRef} style={listLockedHeight ? {
|
| 1669 |
{tutorialTasks.length === 0 && !addingTask ? (
|
| 1670 |
<div className="text-center py-12">
|
| 1671 |
<DocumentTextIcon className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
|
@@ -1896,7 +1913,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 1896 |
<select
|
| 1897 |
value={selectedGroups[task._id] || ''}
|
| 1898 |
onFocus={() => { lockListHeight(); lockCardHeight(task._id); }}
|
| 1899 |
-
onChange={(e) => { lockListHeight(); lockCardHeight(task._id); setSelectedGroups({ ...selectedGroups, [task._id]: parseInt(e.target.value) }); }}
|
| 1900 |
onBlur={() => { unlockCardHeight(task._id); unlockListHeight(); }}
|
| 1901 |
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"
|
| 1902 |
>
|
|
@@ -1913,8 +1930,8 @@ const TutorialTasks: React.FC = () => {
|
|
| 1913 |
id={`tutorial-translation-${task._id}`}
|
| 1914 |
value={translationText[task._id] || ''}
|
| 1915 |
onFocus={() => { lockListHeight(); lockCardHeight(task._id); }}
|
| 1916 |
-
onInput={() => { lockListHeight(); lockCardHeight(task._id); }}
|
| 1917 |
-
onChange={(e) => setTranslationText({ ...translationText, [task._id]: e.target.value })}
|
| 1918 |
onBlur={() => { unlockCardHeight(task._id); unlockListHeight(); }}
|
| 1919 |
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"
|
| 1920 |
style={{ height: sourceHeights[task._id] ? `${sourceHeights[task._id]}px` : 'auto' }}
|
|
@@ -1922,7 +1939,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 1922 |
placeholder="Enter your group's translation here..."
|
| 1923 |
/>
|
| 1924 |
<div className="flex justify-end mt-2">
|
| 1925 |
-
<button onClick={() => { lockListHeight(); lockCardHeight(task._id); handleSubmitTranslation(task._id).finally(() => setTimeout(() => { unlockCardHeight(task._id); unlockListHeight(); }, 300)); }} 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>
|
| 1926 |
</div>
|
| 1927 |
</div>
|
| 1928 |
)}
|
|
|
|
| 73 |
const cardRefs = useRef<{[key: string]: HTMLDivElement | null}>({});
|
| 74 |
const [listLockedHeight, setListLockedHeight] = useState<number | null>(null);
|
| 75 |
const listRef = useRef<HTMLDivElement | null>(null);
|
| 76 |
+
const withPreservedScroll = useRef<(fn: () => void) => void>();
|
| 77 |
+
|
| 78 |
+
// Initialize scroll preservation helper once
|
| 79 |
+
useEffect(() => {
|
| 80 |
+
withPreservedScroll.current = (fn: () => void) => {
|
| 81 |
+
try {
|
| 82 |
+
const y = window.scrollY;
|
| 83 |
+
fn();
|
| 84 |
+
// Restore immediately after next paint
|
| 85 |
+
requestAnimationFrame(() => {
|
| 86 |
+
window.scrollTo(0, y);
|
| 87 |
+
});
|
| 88 |
+
} catch {
|
| 89 |
+
fn();
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
}, []);
|
| 93 |
|
| 94 |
// Move a task up or down by normalizing positions for the current visible list (weeks 4–6 only)
|
| 95 |
const moveTask = async (taskId: string, direction: 'up' | 'down') => {
|
|
|
|
| 1682 |
</div>
|
| 1683 |
)}
|
| 1684 |
|
| 1685 |
+
<div ref={listRef} style={listLockedHeight ? { minHeight: listLockedHeight } : undefined}>
|
| 1686 |
{tutorialTasks.length === 0 && !addingTask ? (
|
| 1687 |
<div className="text-center py-12">
|
| 1688 |
<DocumentTextIcon className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
|
|
|
| 1913 |
<select
|
| 1914 |
value={selectedGroups[task._id] || ''}
|
| 1915 |
onFocus={() => { lockListHeight(); lockCardHeight(task._id); }}
|
| 1916 |
+
onChange={(e) => { lockListHeight(); lockCardHeight(task._id); (withPreservedScroll.current || ((fn)=>fn()))(() => setSelectedGroups({ ...selectedGroups, [task._id]: parseInt(e.target.value) })); }}
|
| 1917 |
onBlur={() => { unlockCardHeight(task._id); unlockListHeight(); }}
|
| 1918 |
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"
|
| 1919 |
>
|
|
|
|
| 1930 |
id={`tutorial-translation-${task._id}`}
|
| 1931 |
value={translationText[task._id] || ''}
|
| 1932 |
onFocus={() => { lockListHeight(); lockCardHeight(task._id); }}
|
| 1933 |
+
onInput={(e) => { lockListHeight(); lockCardHeight(task._id); (withPreservedScroll.current || ((fn)=>fn()))(() => setTranslationText({ ...translationText, [task._id]: (e.target as HTMLTextAreaElement).value })); }}
|
| 1934 |
+
onChange={(e) => (withPreservedScroll.current || ((fn)=>fn()))(() => setTranslationText({ ...translationText, [task._id]: e.target.value }))}
|
| 1935 |
onBlur={() => { unlockCardHeight(task._id); unlockListHeight(); }}
|
| 1936 |
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"
|
| 1937 |
style={{ height: sourceHeights[task._id] ? `${sourceHeights[task._id]}px` : 'auto' }}
|
|
|
|
| 1939 |
placeholder="Enter your group's translation here..."
|
| 1940 |
/>
|
| 1941 |
<div className="flex justify-end mt-2">
|
| 1942 |
+
<button onClick={() => { lockListHeight(); lockCardHeight(task._id); (withPreservedScroll.current || ((fn)=>fn()))(() => {}); handleSubmitTranslation(task._id).finally(() => setTimeout(() => { unlockCardHeight(task._id); unlockListHeight(); }, 300)); }} 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>
|
| 1943 |
</div>
|
| 1944 |
</div>
|
| 1945 |
)}
|