Upload folder using huggingface_hub
Browse files
client/src/pages/TutorialTasks.tsx
CHANGED
|
@@ -170,6 +170,28 @@ const TutorialTasks: React.FC = () => {
|
|
| 170 |
el.style.minHeight = '';
|
| 171 |
};
|
| 172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
const withPreservedCardOffset = (taskId: string, fn: () => void) => {
|
| 174 |
// If scroll is frozen, avoid additional scroll adjustments that can fight WebKit
|
| 175 |
if (scrollLockState.current) {
|
|
@@ -852,11 +874,13 @@ const TutorialTasks: React.FC = () => {
|
|
| 852 |
return;
|
| 853 |
}
|
| 854 |
|
|
|
|
| 855 |
try {
|
| 856 |
setMutatingTaskId(taskId);
|
| 857 |
if (isSafari) {
|
| 858 |
try { (document.activeElement as HTMLElement | null)?.blur?.(); } catch {}
|
| 859 |
freezeScroll();
|
|
|
|
| 860 |
}
|
| 861 |
lockListHeight();
|
| 862 |
lockCardHeightById(taskId);
|
|
@@ -923,7 +947,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 923 |
unlockListHeight();
|
| 924 |
unlockCardHeightById(taskId);
|
| 925 |
unlockGridHeightById(taskId);
|
| 926 |
-
if (isSafari) unfreezeScroll();
|
| 927 |
};
|
| 928 |
if (isSafari) {
|
| 929 |
requestAnimationFrame(() => requestAnimationFrame(() => requestAnimationFrame(release)));
|
|
@@ -975,9 +999,10 @@ const TutorialTasks: React.FC = () => {
|
|
| 975 |
const handleDeleteSubmission = async (submissionId: string, taskId?: string) => {
|
| 976 |
|
| 977 |
|
|
|
|
| 978 |
try {
|
| 979 |
if (taskId) setMutatingTaskId(taskId);
|
| 980 |
-
if (isSafari) freezeScroll();
|
| 981 |
lockListHeight();
|
| 982 |
const response = await api.delete(`/api/submissions/${submissionId}`);
|
| 983 |
|
|
@@ -1028,7 +1053,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 1028 |
unlockCardHeightById(taskId);
|
| 1029 |
unlockGridHeightById(taskId);
|
| 1030 |
}
|
| 1031 |
-
if (isSafari) unfreezeScroll();
|
| 1032 |
setMutatingTaskId(null);
|
| 1033 |
}));
|
| 1034 |
};
|
|
@@ -2295,7 +2320,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 2295 |
|
| 2296 |
{/* All Submissions for this Task */}
|
| 2297 |
{userSubmissions[task._id] && userSubmissions[task._id].length > 0 && (
|
| 2298 |
-
<div ref={(el) => { submissionsContainerRefs.current[task._id] = el; }} className="bg-gradient-to-r from-white to-indigo-50 rounded-xl p-6 mb-6 border border-stone-200" style={{ overflowAnchor: 'none' }}>
|
| 2299 |
<div className="flex items-center justify-between mb-4">
|
| 2300 |
<div className="flex items-center space-x-2">
|
| 2301 |
<div className="bg-indigo-100 rounded-full p-1">
|
|
@@ -2322,7 +2347,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 2322 |
expandedSections[task._id]
|
| 2323 |
? 'max-h-none overflow-visible'
|
| 2324 |
: 'max-h-0 overflow-hidden'
|
| 2325 |
-
}`}>
|
| 2326 |
{userSubmissions[task._id].map((submission, index) => (
|
| 2327 |
<div key={submission._id} className="bg-white rounded-lg p-3 border border-stone-200 flex flex-col justify-between h-full">
|
| 2328 |
<div className="flex items-center justify-between mb-2">
|
|
|
|
| 170 |
el.style.minHeight = '';
|
| 171 |
};
|
| 172 |
|
| 173 |
+
// During volatile mutations on Safari, actively compensate scroll by negating
|
| 174 |
+
// vertical position changes of the task card across a burst of resizes.
|
| 175 |
+
const startCardScrollCompensator = (id: string): (() => void) => {
|
| 176 |
+
try {
|
| 177 |
+
const el = cardRefs.current[id];
|
| 178 |
+
if (!el || typeof ResizeObserver === 'undefined') return () => {};
|
| 179 |
+
let lastTop = el.getBoundingClientRect().top;
|
| 180 |
+
const observer = new ResizeObserver(() => {
|
| 181 |
+
try {
|
| 182 |
+
const currentTop = el.getBoundingClientRect().top;
|
| 183 |
+
const delta = currentTop - lastTop;
|
| 184 |
+
if (delta !== 0) {
|
| 185 |
+
window.scrollBy(0, delta);
|
| 186 |
+
lastTop = currentTop; // keep tracking relative to last applied position
|
| 187 |
+
}
|
| 188 |
+
} catch {}
|
| 189 |
+
});
|
| 190 |
+
observer.observe(el);
|
| 191 |
+
return () => { try { observer.disconnect(); } catch {} };
|
| 192 |
+
} catch { return () => {}; }
|
| 193 |
+
};
|
| 194 |
+
|
| 195 |
const withPreservedCardOffset = (taskId: string, fn: () => void) => {
|
| 196 |
// If scroll is frozen, avoid additional scroll adjustments that can fight WebKit
|
| 197 |
if (scrollLockState.current) {
|
|
|
|
| 874 |
return;
|
| 875 |
}
|
| 876 |
|
| 877 |
+
let stopCompLocal: (() => void) | null = null;
|
| 878 |
try {
|
| 879 |
setMutatingTaskId(taskId);
|
| 880 |
if (isSafari) {
|
| 881 |
try { (document.activeElement as HTMLElement | null)?.blur?.(); } catch {}
|
| 882 |
freezeScroll();
|
| 883 |
+
stopCompLocal = startCardScrollCompensator(taskId);
|
| 884 |
}
|
| 885 |
lockListHeight();
|
| 886 |
lockCardHeightById(taskId);
|
|
|
|
| 947 |
unlockListHeight();
|
| 948 |
unlockCardHeightById(taskId);
|
| 949 |
unlockGridHeightById(taskId);
|
| 950 |
+
if (isSafari) { try { stopCompLocal?.(); } catch {}; unfreezeScroll(); }
|
| 951 |
};
|
| 952 |
if (isSafari) {
|
| 953 |
requestAnimationFrame(() => requestAnimationFrame(() => requestAnimationFrame(release)));
|
|
|
|
| 999 |
const handleDeleteSubmission = async (submissionId: string, taskId?: string) => {
|
| 1000 |
|
| 1001 |
|
| 1002 |
+
let stopCompLocal: (() => void) | null = null;
|
| 1003 |
try {
|
| 1004 |
if (taskId) setMutatingTaskId(taskId);
|
| 1005 |
+
if (isSafari) { freezeScroll(); stopCompLocal = startCardScrollCompensator(taskId || ''); }
|
| 1006 |
lockListHeight();
|
| 1007 |
const response = await api.delete(`/api/submissions/${submissionId}`);
|
| 1008 |
|
|
|
|
| 1053 |
unlockCardHeightById(taskId);
|
| 1054 |
unlockGridHeightById(taskId);
|
| 1055 |
}
|
| 1056 |
+
if (isSafari) { try { stopCompLocal?.(); } catch {}; unfreezeScroll(); }
|
| 1057 |
setMutatingTaskId(null);
|
| 1058 |
}));
|
| 1059 |
};
|
|
|
|
| 2320 |
|
| 2321 |
{/* All Submissions for this Task */}
|
| 2322 |
{userSubmissions[task._id] && userSubmissions[task._id].length > 0 && (
|
| 2323 |
+
<div ref={(el) => { submissionsContainerRefs.current[task._id] = el; }} className="bg-gradient-to-r from-white to-indigo-50 rounded-xl p-6 mb-6 border border-stone-200" style={{ overflowAnchor: 'none', contain: isSafari ? ('layout paint size' as any) : undefined, transform: isSafari ? 'translateZ(0)' : undefined, willChange: isSafari ? ('contents' as any) : undefined }}>
|
| 2324 |
<div className="flex items-center justify-between mb-4">
|
| 2325 |
<div className="flex items-center space-x-2">
|
| 2326 |
<div className="bg-indigo-100 rounded-full p-1">
|
|
|
|
| 2347 |
expandedSections[task._id]
|
| 2348 |
? 'max-h-none overflow-visible'
|
| 2349 |
: 'max-h-0 overflow-hidden'
|
| 2350 |
+
}`} style={{ contain: isSafari ? ('layout paint size' as any) : undefined, transform: isSafari ? 'translateZ(0)' : undefined, willChange: isSafari ? ('contents' as any) : undefined }}>
|
| 2351 |
{userSubmissions[task._id].map((submission, index) => (
|
| 2352 |
<div key={submission._id} className="bg-white rounded-lg p-3 border border-stone-200 flex flex-col justify-between h-full">
|
| 2353 |
<div className="flex items-center justify-between mb-2">
|