Commit
·
19a56ad
1
Parent(s):
8be71fe
add missing tasks and improve style
Browse files
app.py
CHANGED
@@ -294,7 +294,11 @@ class TransformersTimelineParser:
|
|
294 |
# Import the model mappings from transformers
|
295 |
from transformers.models.auto.modeling_auto import (
|
296 |
MODEL_FOR_AUDIO_CLASSIFICATION_MAPPING_NAMES,
|
|
|
|
|
|
|
297 |
MODEL_FOR_CAUSAL_LM_MAPPING_NAMES,
|
|
|
298 |
MODEL_FOR_DEPTH_ESTIMATION_MAPPING_NAMES,
|
299 |
MODEL_FOR_DOCUMENT_QUESTION_ANSWERING_MAPPING_NAMES,
|
300 |
MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING_NAMES,
|
@@ -302,15 +306,21 @@ class TransformersTimelineParser:
|
|
302 |
MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES,
|
303 |
MODEL_FOR_IMAGE_TO_IMAGE_MAPPING_NAMES,
|
304 |
MODEL_FOR_INSTANCE_SEGMENTATION_MAPPING_NAMES,
|
|
|
|
|
305 |
MODEL_FOR_MASK_GENERATION_MAPPING_NAMES,
|
|
|
306 |
MODEL_FOR_MASKED_LM_MAPPING_NAMES,
|
|
|
307 |
MODEL_FOR_OBJECT_DETECTION_MAPPING_NAMES,
|
308 |
MODEL_FOR_QUESTION_ANSWERING_MAPPING_NAMES,
|
309 |
MODEL_FOR_SEMANTIC_SEGMENTATION_MAPPING_NAMES,
|
310 |
MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING_NAMES,
|
311 |
MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING_NAMES,
|
|
|
312 |
MODEL_FOR_TABLE_QUESTION_ANSWERING_MAPPING_NAMES,
|
313 |
MODEL_FOR_TEXT_TO_SPECTROGRAM_MAPPING_NAMES,
|
|
|
314 |
MODEL_FOR_TIME_SERIES_CLASSIFICATION_MAPPING_NAMES,
|
315 |
MODEL_FOR_TIME_SERIES_PREDICTION_MAPPING_NAMES,
|
316 |
MODEL_FOR_TIME_SERIES_REGRESSION_MAPPING_NAMES,
|
@@ -331,6 +341,7 @@ class TransformersTimelineParser:
|
|
331 |
"question-answering": MODEL_FOR_QUESTION_ANSWERING_MAPPING_NAMES,
|
332 |
"fill-mask": MODEL_FOR_MASKED_LM_MAPPING_NAMES,
|
333 |
"text2text-generation": MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING_NAMES,
|
|
|
334 |
"image-classification": MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING_NAMES,
|
335 |
"object-detection": MODEL_FOR_OBJECT_DETECTION_MAPPING_NAMES,
|
336 |
"image-segmentation": MODEL_FOR_IMAGE_SEGMENTATION_MAPPING_NAMES,
|
@@ -338,8 +349,16 @@ class TransformersTimelineParser:
|
|
338 |
"instance-segmentation": MODEL_FOR_INSTANCE_SEGMENTATION_MAPPING_NAMES,
|
339 |
"universal-segmentation": MODEL_FOR_UNIVERSAL_SEGMENTATION_MAPPING_NAMES,
|
340 |
"depth-estimation": MODEL_FOR_DEPTH_ESTIMATION_MAPPING_NAMES,
|
|
|
|
|
|
|
|
|
341 |
"video-classification": MODEL_FOR_VIDEO_CLASSIFICATION_MAPPING_NAMES,
|
342 |
"audio-classification": MODEL_FOR_AUDIO_CLASSIFICATION_MAPPING_NAMES,
|
|
|
|
|
|
|
|
|
343 |
"image-to-text": MODEL_FOR_VISION_2_SEQ_MAPPING_NAMES,
|
344 |
"image-text-to-text": MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES,
|
345 |
"visual-question-answering": MODEL_FOR_VISUAL_QUESTION_ANSWERING_MAPPING_NAMES,
|
@@ -350,6 +369,7 @@ class TransformersTimelineParser:
|
|
350 |
"image-to-image": MODEL_FOR_IMAGE_TO_IMAGE_MAPPING_NAMES,
|
351 |
"mask-generation": MODEL_FOR_MASK_GENERATION_MAPPING_NAMES,
|
352 |
"text-to-audio": MODEL_FOR_TEXT_TO_SPECTROGRAM_MAPPING_NAMES,
|
|
|
353 |
"time-series-classification": MODEL_FOR_TIME_SERIES_CLASSIFICATION_MAPPING_NAMES,
|
354 |
"time-series-regression": MODEL_FOR_TIME_SERIES_REGRESSION_MAPPING_NAMES,
|
355 |
"time-series-prediction": MODEL_FOR_TIME_SERIES_PREDICTION_MAPPING_NAMES,
|
@@ -536,6 +556,7 @@ def get_tasks():
|
|
536 |
"question-answering": {"name": "Question Answering", "color": "#c084fc"},
|
537 |
"fill-mask": {"name": "Fill Mask", "color": "#d8b4fe"},
|
538 |
"text2text-generation": {"name": "Text2Text Generation", "color": "#e879f9"},
|
|
|
539 |
"image-classification": {"name": "Image Classification", "color": "#06b6d4"},
|
540 |
"object-detection": {"name": "Object Detection", "color": "#0891b2"},
|
541 |
"image-segmentation": {"name": "Image Segmentation", "color": "#0e7490"},
|
@@ -543,6 +564,10 @@ def get_tasks():
|
|
543 |
"instance-segmentation": {"name": "Instance Segmentation", "color": "#164e63"},
|
544 |
"universal-segmentation": {"name": "Universal Segmentation", "color": "#1e40af"},
|
545 |
"depth-estimation": {"name": "Depth Estimation", "color": "#1d4ed8"},
|
|
|
|
|
|
|
|
|
546 |
"zero-shot-image-classification": {"name": "Zero-Shot Image Classification", "color": "#2563eb"},
|
547 |
"zero-shot-object-detection": {"name": "Zero-Shot Object Detection", "color": "#3b82f6"},
|
548 |
"image-to-image": {"name": "Image to Image", "color": "#60a5fa"},
|
@@ -554,7 +579,15 @@ def get_tasks():
|
|
554 |
"table-question-answering": {"name": "Table Question Answering", "color": "#064e3b"},
|
555 |
"video-classification": {"name": "Video Classification", "color": "#dc2626"},
|
556 |
"audio-classification": {"name": "Audio Classification", "color": "#ea580c"},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
557 |
"text-to-audio": {"name": "Text to Audio", "color": "#f97316"},
|
|
|
558 |
"time-series-classification": {"name": "Time Series Classification", "color": "#84cc16"},
|
559 |
"time-series-regression": {"name": "Time Series Regression", "color": "#65a30d"},
|
560 |
"time-series-prediction": {"name": "Time Series Prediction", "color": "#4d7c0f"},
|
@@ -604,7 +637,8 @@ def create_timeline_template():
|
|
604 |
body {
|
605 |
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
606 |
background: linear-gradient(135deg, #fef3c7 0%, #fed7aa 100%);
|
607 |
-
|
|
|
608 |
color: #333;
|
609 |
display: flex;
|
610 |
flex-direction: column;
|
@@ -1198,7 +1232,7 @@ def create_timeline_template():
|
|
1198 |
flex: 1;
|
1199 |
display: flex;
|
1200 |
flex-direction: column;
|
1201 |
-
height:
|
1202 |
transition: all 0.3s ease;
|
1203 |
}
|
1204 |
|
@@ -1409,23 +1443,22 @@ def create_timeline_template():
|
|
1409 |
position: absolute;
|
1410 |
top: 0;
|
1411 |
bottom: 0;
|
1412 |
-
width:
|
1413 |
-
|
1414 |
-
opacity: 0.
|
1415 |
pointer-events: none;
|
1416 |
-
z-index: 1; /* In background, below everything */
|
1417 |
transition: all 0.3s ease;
|
1418 |
}
|
1419 |
|
1420 |
/* Dark mode date markers */
|
1421 |
[data-theme="dark"] .date-marker {
|
1422 |
-
|
1423 |
-
opacity: 0.
|
1424 |
}
|
1425 |
|
1426 |
.date-label {
|
1427 |
position: absolute;
|
1428 |
-
top:
|
1429 |
left: 8px; /* Offset to the right of the line */
|
1430 |
font-size: 0.75rem;
|
1431 |
color: #6b7280;
|
@@ -1437,7 +1470,7 @@ def create_timeline_template():
|
|
1437 |
border: 1px solid rgba(156, 163, 175, 0.4);
|
1438 |
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
1439 |
white-space: nowrap;
|
1440 |
-
z-index:
|
1441 |
backdrop-filter: blur(4px);
|
1442 |
transition: all 0.3s ease;
|
1443 |
}
|
@@ -1451,15 +1484,15 @@ def create_timeline_template():
|
|
1451 |
}
|
1452 |
|
1453 |
.date-marker.year {
|
1454 |
-
opacity: 0.
|
1455 |
-
|
1456 |
-
width:
|
1457 |
}
|
1458 |
|
1459 |
/* Dark mode year markers */
|
1460 |
[data-theme="dark"] .date-marker.year {
|
1461 |
-
|
1462 |
-
opacity:
|
1463 |
}
|
1464 |
|
1465 |
.date-marker.year .date-label {
|
@@ -2203,6 +2236,76 @@ def create_timeline_template():
|
|
2203 |
const maxZoom = 3.0; // Maximum zoom (300%)
|
2204 |
let taskData = {}; // Store task data for easy lookup
|
2205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2206 |
// Theme management
|
2207 |
let currentTheme = 'light';
|
2208 |
|
@@ -2433,6 +2536,9 @@ def create_timeline_template():
|
|
2433 |
// Add date markers before adding models
|
2434 |
addDateMarkers(sortedModels, actualSpacing);
|
2435 |
|
|
|
|
|
|
|
2436 |
// Create wave patterns for stacking - simpler pattern
|
2437 |
const abovePattern = [1, 2, 3]; // 3 levels above
|
2438 |
const belowPattern = [1, 2, 3]; // 3 levels below
|
@@ -2461,6 +2567,19 @@ def create_timeline_template():
|
|
2461 |
item.className = `timeline-item ${positionClass}`;
|
2462 |
item.style.left = position + 'px';
|
2463 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2464 |
const dot = document.createElement('div');
|
2465 |
dot.className = 'timeline-dot';
|
2466 |
|
@@ -2480,12 +2599,31 @@ def create_timeline_template():
|
|
2480 |
|
2481 |
const connector = document.createElement('div');
|
2482 |
connector.className = 'timeline-connector';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2483 |
|
2484 |
const label = document.createElement('div');
|
2485 |
label.className = 'timeline-label';
|
2486 |
label.style.borderLeftColor = model.modality_color || '#8B5CF6';
|
2487 |
// Set the modality color as a CSS custom property for hover effects
|
2488 |
label.style.setProperty('--modality-color', model.modality_color || '#8B5CF6');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2489 |
|
2490 |
// Ensure the model name is always displayed
|
2491 |
const modelName = model.display_name || model.model_name || 'Unknown Model';
|
@@ -2529,10 +2667,17 @@ def create_timeline_template():
|
|
2529 |
<div class="timeline-date">${otherLabel.dataset.modelDate}</div>
|
2530 |
`;
|
2531 |
|
2532 |
-
//
|
2533 |
setTimeout(() => {
|
2534 |
-
|
2535 |
-
otherLabel.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2536 |
otherLabel.style.left = '';
|
2537 |
otherLabel.style.right = '';
|
2538 |
otherLabel.style.transform = 'translateX(-50%)';
|
@@ -2659,10 +2804,17 @@ def create_timeline_template():
|
|
2659 |
<div class="timeline-date">${label.dataset.modelDate}</div>
|
2660 |
`;
|
2661 |
|
2662 |
-
//
|
2663 |
setTimeout(() => {
|
2664 |
-
|
2665 |
-
label.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2666 |
label.style.left = '';
|
2667 |
label.style.right = '';
|
2668 |
// Reset transform: depends on current position
|
@@ -2816,11 +2968,8 @@ def create_timeline_template():
|
|
2816 |
// Check if the marker date falls between these two models
|
2817 |
// The marker should appear where the time period actually starts
|
2818 |
if (currentModelDate < currentDate && currentDate <= nextModelDate) {
|
2819 |
-
// Position the marker between these two models
|
2820 |
-
|
2821 |
-
const nextPos = (i + 1) * spacing + 100;
|
2822 |
-
const midpoint = (currentPos + nextPos) / 2;
|
2823 |
-
boundaryPosition = midpoint - (spacing / 2); // Move left by half segment length
|
2824 |
break;
|
2825 |
}
|
2826 |
}
|
@@ -2839,45 +2988,64 @@ def create_timeline_template():
|
|
2839 |
const position = boundaryPosition;
|
2840 |
|
2841 |
// Create marker only if it's within visible range and not too close to adjacent markers
|
|
|
2842 |
const existingMarkers = timeline.querySelectorAll('.date-marker');
|
2843 |
-
let
|
2844 |
-
|
2845 |
-
|
2846 |
-
|
2847 |
-
|
|
|
|
|
|
|
|
|
2848 |
}
|
2849 |
-
}
|
2850 |
|
2851 |
-
if (
|
2852 |
-
|
2853 |
-
marker
|
2854 |
-
|
2855 |
-
|
2856 |
-
|
2857 |
-
|
2858 |
-
|
2859 |
-
|
2860 |
-
|
2861 |
-
|
2862 |
-
|
2863 |
-
const line = document.createElement('div');
|
2864 |
-
line.style.position = 'absolute';
|
2865 |
-
line.style.top = '0px';
|
2866 |
-
line.style.bottom = '0px';
|
2867 |
-
line.style.left = '0px';
|
2868 |
-
line.style.width = '2px';
|
2869 |
-
line.style.background = '#9ca3af';
|
2870 |
-
line.style.opacity = '0.6';
|
2871 |
-
line.style.zIndex = '1';
|
2872 |
-
if (markerType === 'year') {
|
2873 |
-
line.style.width = '3px';
|
2874 |
-
line.style.background = '#6b7280';
|
2875 |
-
line.style.opacity = '0.8';
|
2876 |
}
|
2877 |
-
|
2878 |
|
2879 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2880 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2881 |
|
2882 |
// Move to next marker
|
2883 |
currentDate.setMonth(currentDate.getMonth() + increment);
|
@@ -3161,6 +3329,7 @@ def create_timeline_template():
|
|
3161 |
"question-answering": "#c084fc",
|
3162 |
"fill-mask": "#d8b4fe",
|
3163 |
"text2text-generation": "#e879f9",
|
|
|
3164 |
|
3165 |
"image-classification": "#06b6d4",
|
3166 |
"object-detection": "#0891b2",
|
@@ -3169,6 +3338,10 @@ def create_timeline_template():
|
|
3169 |
"instance-segmentation": "#164e63",
|
3170 |
"universal-segmentation": "#1e40af",
|
3171 |
"depth-estimation": "#1d4ed8",
|
|
|
|
|
|
|
|
|
3172 |
"zero-shot-image-classification": "#2563eb",
|
3173 |
"zero-shot-object-detection": "#3b82f6",
|
3174 |
"image-to-image": "#60a5fa",
|
@@ -3182,7 +3355,12 @@ def create_timeline_template():
|
|
3182 |
|
3183 |
"video-classification": "#dc2626",
|
3184 |
"audio-classification": "#ea580c",
|
|
|
|
|
|
|
|
|
3185 |
"text-to-audio": "#f97316",
|
|
|
3186 |
|
3187 |
"time-series-classification": "#84cc16",
|
3188 |
"time-series-regression": "#65a30d",
|
@@ -3225,7 +3403,7 @@ def create_timeline_template():
|
|
3225 |
checkbox.type = 'checkbox';
|
3226 |
checkbox.value = modality.key;
|
3227 |
checkbox.id = `modality-${modality.key}`;
|
3228 |
-
checkbox.checked =
|
3229 |
|
3230 |
const label = document.createElement('label');
|
3231 |
label.htmlFor = `modality-${modality.key}`;
|
@@ -3244,8 +3422,7 @@ def create_timeline_template():
|
|
3244 |
loadTimeline();
|
3245 |
});
|
3246 |
|
3247 |
-
// Set initial state
|
3248 |
-
checkboxContainer.classList.add('checked');
|
3249 |
|
3250 |
modalityFilters.appendChild(checkboxContainer);
|
3251 |
});
|
@@ -3255,11 +3432,19 @@ def create_timeline_template():
|
|
3255 |
}
|
3256 |
}
|
3257 |
|
3258 |
-
// Window resize handler
|
|
|
3259 |
window.addEventListener('resize', () => {
|
3260 |
-
|
3261 |
-
|
3262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3263 |
});
|
3264 |
|
3265 |
document.addEventListener('DOMContentLoaded', async () => {
|
@@ -3304,10 +3489,17 @@ def create_timeline_template():
|
|
3304 |
<div class="timeline-date">${label.dataset.modelDate}</div>
|
3305 |
`;
|
3306 |
|
3307 |
-
//
|
3308 |
setTimeout(() => {
|
3309 |
-
|
3310 |
-
label.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3311 |
label.style.transform = 'translateX(-50%)';
|
3312 |
label.parentElement.style.zIndex = '';
|
3313 |
}, 50);
|
@@ -3364,6 +3556,27 @@ def create_timeline_template():
|
|
3364 |
btn.textContent = '▸';
|
3365 |
localStorage.setItem('filtersCollapsed', 'true');
|
3366 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3367 |
}
|
3368 |
</script>
|
3369 |
</body>
|
|
|
294 |
# Import the model mappings from transformers
|
295 |
from transformers.models.auto.modeling_auto import (
|
296 |
MODEL_FOR_AUDIO_CLASSIFICATION_MAPPING_NAMES,
|
297 |
+
MODEL_FOR_AUDIO_FRAME_CLASSIFICATION_MAPPING_NAMES,
|
298 |
+
MODEL_FOR_AUDIO_XVECTOR_MAPPING_NAMES,
|
299 |
+
MODEL_FOR_CAUSAL_IMAGE_MODELING_MAPPING_NAMES,
|
300 |
MODEL_FOR_CAUSAL_LM_MAPPING_NAMES,
|
301 |
+
MODEL_FOR_CTC_MAPPING_NAMES,
|
302 |
MODEL_FOR_DEPTH_ESTIMATION_MAPPING_NAMES,
|
303 |
MODEL_FOR_DOCUMENT_QUESTION_ANSWERING_MAPPING_NAMES,
|
304 |
MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING_NAMES,
|
|
|
306 |
MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES,
|
307 |
MODEL_FOR_IMAGE_TO_IMAGE_MAPPING_NAMES,
|
308 |
MODEL_FOR_INSTANCE_SEGMENTATION_MAPPING_NAMES,
|
309 |
+
MODEL_FOR_KEYPOINT_DETECTION_MAPPING_NAMES,
|
310 |
+
MODEL_FOR_KEYPOINT_MATCHING_MAPPING_NAMES,
|
311 |
MODEL_FOR_MASK_GENERATION_MAPPING_NAMES,
|
312 |
+
MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING_NAMES,
|
313 |
MODEL_FOR_MASKED_LM_MAPPING_NAMES,
|
314 |
+
MODEL_FOR_MULTIPLE_CHOICE_MAPPING_NAMES,
|
315 |
MODEL_FOR_OBJECT_DETECTION_MAPPING_NAMES,
|
316 |
MODEL_FOR_QUESTION_ANSWERING_MAPPING_NAMES,
|
317 |
MODEL_FOR_SEMANTIC_SEGMENTATION_MAPPING_NAMES,
|
318 |
MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING_NAMES,
|
319 |
MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING_NAMES,
|
320 |
+
MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING_NAMES,
|
321 |
MODEL_FOR_TABLE_QUESTION_ANSWERING_MAPPING_NAMES,
|
322 |
MODEL_FOR_TEXT_TO_SPECTROGRAM_MAPPING_NAMES,
|
323 |
+
MODEL_FOR_TEXT_TO_WAVEFORM_MAPPING_NAMES,
|
324 |
MODEL_FOR_TIME_SERIES_CLASSIFICATION_MAPPING_NAMES,
|
325 |
MODEL_FOR_TIME_SERIES_PREDICTION_MAPPING_NAMES,
|
326 |
MODEL_FOR_TIME_SERIES_REGRESSION_MAPPING_NAMES,
|
|
|
341 |
"question-answering": MODEL_FOR_QUESTION_ANSWERING_MAPPING_NAMES,
|
342 |
"fill-mask": MODEL_FOR_MASKED_LM_MAPPING_NAMES,
|
343 |
"text2text-generation": MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING_NAMES,
|
344 |
+
"multiple-choice": MODEL_FOR_MULTIPLE_CHOICE_MAPPING_NAMES,
|
345 |
"image-classification": MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING_NAMES,
|
346 |
"object-detection": MODEL_FOR_OBJECT_DETECTION_MAPPING_NAMES,
|
347 |
"image-segmentation": MODEL_FOR_IMAGE_SEGMENTATION_MAPPING_NAMES,
|
|
|
349 |
"instance-segmentation": MODEL_FOR_INSTANCE_SEGMENTATION_MAPPING_NAMES,
|
350 |
"universal-segmentation": MODEL_FOR_UNIVERSAL_SEGMENTATION_MAPPING_NAMES,
|
351 |
"depth-estimation": MODEL_FOR_DEPTH_ESTIMATION_MAPPING_NAMES,
|
352 |
+
"masked-image-modeling": MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING_NAMES,
|
353 |
+
"causal-image-modeling": MODEL_FOR_CAUSAL_IMAGE_MODELING_MAPPING_NAMES,
|
354 |
+
"keypoint-detection": MODEL_FOR_KEYPOINT_DETECTION_MAPPING_NAMES,
|
355 |
+
"keypoint-matching": MODEL_FOR_KEYPOINT_MATCHING_MAPPING_NAMES,
|
356 |
"video-classification": MODEL_FOR_VIDEO_CLASSIFICATION_MAPPING_NAMES,
|
357 |
"audio-classification": MODEL_FOR_AUDIO_CLASSIFICATION_MAPPING_NAMES,
|
358 |
+
"audio-frame-classification": MODEL_FOR_AUDIO_FRAME_CLASSIFICATION_MAPPING_NAMES,
|
359 |
+
"audio-xvector": MODEL_FOR_AUDIO_XVECTOR_MAPPING_NAMES,
|
360 |
+
"automatic-speech-recognition": MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING_NAMES,
|
361 |
+
"connectionist-temporal-classification": MODEL_FOR_CTC_MAPPING_NAMES,
|
362 |
"image-to-text": MODEL_FOR_VISION_2_SEQ_MAPPING_NAMES,
|
363 |
"image-text-to-text": MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES,
|
364 |
"visual-question-answering": MODEL_FOR_VISUAL_QUESTION_ANSWERING_MAPPING_NAMES,
|
|
|
369 |
"image-to-image": MODEL_FOR_IMAGE_TO_IMAGE_MAPPING_NAMES,
|
370 |
"mask-generation": MODEL_FOR_MASK_GENERATION_MAPPING_NAMES,
|
371 |
"text-to-audio": MODEL_FOR_TEXT_TO_SPECTROGRAM_MAPPING_NAMES,
|
372 |
+
"text-to-waveform": MODEL_FOR_TEXT_TO_WAVEFORM_MAPPING_NAMES,
|
373 |
"time-series-classification": MODEL_FOR_TIME_SERIES_CLASSIFICATION_MAPPING_NAMES,
|
374 |
"time-series-regression": MODEL_FOR_TIME_SERIES_REGRESSION_MAPPING_NAMES,
|
375 |
"time-series-prediction": MODEL_FOR_TIME_SERIES_PREDICTION_MAPPING_NAMES,
|
|
|
556 |
"question-answering": {"name": "Question Answering", "color": "#c084fc"},
|
557 |
"fill-mask": {"name": "Fill Mask", "color": "#d8b4fe"},
|
558 |
"text2text-generation": {"name": "Text2Text Generation", "color": "#e879f9"},
|
559 |
+
"multiple-choice": {"name": "Multiple Choice", "color": "#c026d3"},
|
560 |
"image-classification": {"name": "Image Classification", "color": "#06b6d4"},
|
561 |
"object-detection": {"name": "Object Detection", "color": "#0891b2"},
|
562 |
"image-segmentation": {"name": "Image Segmentation", "color": "#0e7490"},
|
|
|
564 |
"instance-segmentation": {"name": "Instance Segmentation", "color": "#164e63"},
|
565 |
"universal-segmentation": {"name": "Universal Segmentation", "color": "#1e40af"},
|
566 |
"depth-estimation": {"name": "Depth Estimation", "color": "#1d4ed8"},
|
567 |
+
"masked-image-modeling": {"name": "Masked Image Modeling", "color": "#7c3aed"},
|
568 |
+
"causal-image-modeling": {"name": "Causal Image Modeling", "color": "#6d28d9"},
|
569 |
+
"keypoint-detection": {"name": "Keypoint Detection", "color": "#4338ca"},
|
570 |
+
"keypoint-matching": {"name": "Keypoint Matching", "color": "#3730a3"},
|
571 |
"zero-shot-image-classification": {"name": "Zero-Shot Image Classification", "color": "#2563eb"},
|
572 |
"zero-shot-object-detection": {"name": "Zero-Shot Object Detection", "color": "#3b82f6"},
|
573 |
"image-to-image": {"name": "Image to Image", "color": "#60a5fa"},
|
|
|
579 |
"table-question-answering": {"name": "Table Question Answering", "color": "#064e3b"},
|
580 |
"video-classification": {"name": "Video Classification", "color": "#dc2626"},
|
581 |
"audio-classification": {"name": "Audio Classification", "color": "#ea580c"},
|
582 |
+
"audio-frame-classification": {"name": "Audio Frame Classification", "color": "#fb923c"},
|
583 |
+
"audio-xvector": {"name": "Audio X-Vector", "color": "#fdba74"},
|
584 |
+
"automatic-speech-recognition": {"name": "Automatic Speech Recognition", "color": "#e11d48"},
|
585 |
+
"connectionist-temporal-classification": {
|
586 |
+
"name": "Connectionist Temporal Classification",
|
587 |
+
"color": "#be123c",
|
588 |
+
},
|
589 |
"text-to-audio": {"name": "Text to Audio", "color": "#f97316"},
|
590 |
+
"text-to-waveform": {"name": "Text to Waveform", "color": "#fb923c"},
|
591 |
"time-series-classification": {"name": "Time Series Classification", "color": "#84cc16"},
|
592 |
"time-series-regression": {"name": "Time Series Regression", "color": "#65a30d"},
|
593 |
"time-series-prediction": {"name": "Time Series Prediction", "color": "#4d7c0f"},
|
|
|
637 |
body {
|
638 |
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
639 |
background: linear-gradient(135deg, #fef3c7 0%, #fed7aa 100%);
|
640 |
+
height: 100vh;
|
641 |
+
overflow: hidden;
|
642 |
color: #333;
|
643 |
display: flex;
|
644 |
flex-direction: column;
|
|
|
1232 |
flex: 1;
|
1233 |
display: flex;
|
1234 |
flex-direction: column;
|
1235 |
+
min-height: 400px;
|
1236 |
transition: all 0.3s ease;
|
1237 |
}
|
1238 |
|
|
|
1443 |
position: absolute;
|
1444 |
top: 0;
|
1445 |
bottom: 0;
|
1446 |
+
width: 1px;
|
1447 |
+
border-left: 1px dashed #9ca3af;
|
1448 |
+
opacity: 0.5;
|
1449 |
pointer-events: none;
|
|
|
1450 |
transition: all 0.3s ease;
|
1451 |
}
|
1452 |
|
1453 |
/* Dark mode date markers */
|
1454 |
[data-theme="dark"] .date-marker {
|
1455 |
+
border-left-color: #6b7280;
|
1456 |
+
opacity: 0.6;
|
1457 |
}
|
1458 |
|
1459 |
.date-label {
|
1460 |
position: absolute;
|
1461 |
+
top: 10px; /* Near the top of timeline viewport */
|
1462 |
left: 8px; /* Offset to the right of the line */
|
1463 |
font-size: 0.75rem;
|
1464 |
color: #6b7280;
|
|
|
1470 |
border: 1px solid rgba(156, 163, 175, 0.4);
|
1471 |
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
1472 |
white-space: nowrap;
|
1473 |
+
z-index: 9; /* Just above the dotted line but below cards */
|
1474 |
backdrop-filter: blur(4px);
|
1475 |
transition: all 0.3s ease;
|
1476 |
}
|
|
|
1484 |
}
|
1485 |
|
1486 |
.date-marker.year {
|
1487 |
+
opacity: 0.7;
|
1488 |
+
border-left: 1px dashed #6b7280;
|
1489 |
+
width: 1px;
|
1490 |
}
|
1491 |
|
1492 |
/* Dark mode year markers */
|
1493 |
[data-theme="dark"] .date-marker.year {
|
1494 |
+
border-left-color: #9ca3af;
|
1495 |
+
opacity: 0.8;
|
1496 |
}
|
1497 |
|
1498 |
.date-marker.year .date-label {
|
|
|
2236 |
const maxZoom = 3.0; // Maximum zoom (300%)
|
2237 |
let taskData = {}; // Store task data for easy lookup
|
2238 |
|
2239 |
+
// Function to calculate dynamic card spacing based on available height
|
2240 |
+
function getCardSpacing() {
|
2241 |
+
const timelineWrapper = document.querySelector('.timeline-wrapper');
|
2242 |
+
if (!timelineWrapper) return { above: [60, 120, 180], below: [60, 120, 180] };
|
2243 |
+
|
2244 |
+
const availableHeight = timelineWrapper.clientHeight;
|
2245 |
+
const centerLineOffset = availableHeight / 2;
|
2246 |
+
const usableHeight = Math.max(centerLineOffset - 80, 80); // Leave margin for card height
|
2247 |
+
|
2248 |
+
// Calculate spacing between levels (3 levels each side)
|
2249 |
+
// Use the minimum of: default spacing OR available space divided by 3
|
2250 |
+
const levelSpacing = Math.max(40, Math.min(60, usableHeight / 3)); // At least 40px, max 60px
|
2251 |
+
|
2252 |
+
return {
|
2253 |
+
above: [
|
2254 |
+
levelSpacing,
|
2255 |
+
levelSpacing * 2,
|
2256 |
+
levelSpacing * 3
|
2257 |
+
],
|
2258 |
+
below: [
|
2259 |
+
levelSpacing,
|
2260 |
+
levelSpacing * 2,
|
2261 |
+
levelSpacing * 3
|
2262 |
+
]
|
2263 |
+
};
|
2264 |
+
}
|
2265 |
+
|
2266 |
+
// Efficiently update card positions without re-rendering
|
2267 |
+
function updateCardPositions() {
|
2268 |
+
const cardSpacing = getCardSpacing();
|
2269 |
+
const timeline = document.getElementById('timeline');
|
2270 |
+
if (!timeline) return;
|
2271 |
+
|
2272 |
+
// Update all timeline items
|
2273 |
+
const items = timeline.querySelectorAll('.timeline-item');
|
2274 |
+
items.forEach(item => {
|
2275 |
+
const positionClass = item.className.match(/(above|below)-(\\d)/);
|
2276 |
+
if (!positionClass) return;
|
2277 |
+
|
2278 |
+
const isAbove = positionClass[1] === 'above';
|
2279 |
+
const level = parseInt(positionClass[2]) - 1; // 0, 1, or 2
|
2280 |
+
|
2281 |
+
// Update connector height
|
2282 |
+
const connector = item.querySelector('.timeline-connector');
|
2283 |
+
if (connector) {
|
2284 |
+
if (isAbove) {
|
2285 |
+
connector.style.height = cardSpacing.above[level] + 'px';
|
2286 |
+
} else {
|
2287 |
+
connector.style.height = cardSpacing.below[level] + 'px';
|
2288 |
+
}
|
2289 |
+
}
|
2290 |
+
|
2291 |
+
// Update label position
|
2292 |
+
const label = item.querySelector('.timeline-label');
|
2293 |
+
if (label) {
|
2294 |
+
if (isAbove) {
|
2295 |
+
const dynamicBottom = cardSpacing.above[level] + 'px';
|
2296 |
+
label.style.bottom = dynamicBottom;
|
2297 |
+
label.style.top = '';
|
2298 |
+
label.dataset.dynamicBottom = dynamicBottom;
|
2299 |
+
} else {
|
2300 |
+
const dynamicTop = cardSpacing.below[level] + 'px';
|
2301 |
+
label.style.top = dynamicTop;
|
2302 |
+
label.style.bottom = '';
|
2303 |
+
label.dataset.dynamicTop = dynamicTop;
|
2304 |
+
}
|
2305 |
+
}
|
2306 |
+
});
|
2307 |
+
}
|
2308 |
+
|
2309 |
// Theme management
|
2310 |
let currentTheme = 'light';
|
2311 |
|
|
|
2536 |
// Add date markers before adding models
|
2537 |
addDateMarkers(sortedModels, actualSpacing);
|
2538 |
|
2539 |
+
// Get dynamic card spacing based on available height
|
2540 |
+
const cardSpacing = getCardSpacing();
|
2541 |
+
|
2542 |
// Create wave patterns for stacking - simpler pattern
|
2543 |
const abovePattern = [1, 2, 3]; // 3 levels above
|
2544 |
const belowPattern = [1, 2, 3]; // 3 levels below
|
|
|
2567 |
item.className = `timeline-item ${positionClass}`;
|
2568 |
item.style.left = position + 'px';
|
2569 |
|
2570 |
+
// Apply dynamic positioning based on available height
|
2571 |
+
const levelIndex = parseInt(positionClass.split('-')[1]) - 1; // Get 0, 1, or 2
|
2572 |
+
const isAbove = positionClass.includes('above');
|
2573 |
+
|
2574 |
+
// Store the dynamic spacing as data attributes for later use
|
2575 |
+
if (isAbove) {
|
2576 |
+
item.dataset.dynamicBottom = cardSpacing.above[levelIndex] + 'px';
|
2577 |
+
item.dataset.dynamicHeight = cardSpacing.above[levelIndex] + 'px';
|
2578 |
+
} else {
|
2579 |
+
item.dataset.dynamicTop = cardSpacing.below[levelIndex] + 'px';
|
2580 |
+
item.dataset.dynamicHeight = cardSpacing.below[levelIndex] + 'px';
|
2581 |
+
}
|
2582 |
+
|
2583 |
const dot = document.createElement('div');
|
2584 |
dot.className = 'timeline-dot';
|
2585 |
|
|
|
2599 |
|
2600 |
const connector = document.createElement('div');
|
2601 |
connector.className = 'timeline-connector';
|
2602 |
+
// Apply dynamic height to connector
|
2603 |
+
if (isAbove) {
|
2604 |
+
connector.style.bottom = '9px';
|
2605 |
+
connector.style.height = cardSpacing.above[levelIndex] + 'px';
|
2606 |
+
} else {
|
2607 |
+
connector.style.top = '9px';
|
2608 |
+
connector.style.height = cardSpacing.below[levelIndex] + 'px';
|
2609 |
+
}
|
2610 |
|
2611 |
const label = document.createElement('div');
|
2612 |
label.className = 'timeline-label';
|
2613 |
label.style.borderLeftColor = model.modality_color || '#8B5CF6';
|
2614 |
// Set the modality color as a CSS custom property for hover effects
|
2615 |
label.style.setProperty('--modality-color', model.modality_color || '#8B5CF6');
|
2616 |
+
// Apply dynamic positioning to label and store for later restoration
|
2617 |
+
if (isAbove) {
|
2618 |
+
const dynamicBottom = cardSpacing.above[levelIndex] + 'px';
|
2619 |
+
label.style.bottom = dynamicBottom;
|
2620 |
+
label.dataset.dynamicBottom = dynamicBottom;
|
2621 |
+
} else {
|
2622 |
+
const dynamicTop = cardSpacing.below[levelIndex] + 'px';
|
2623 |
+
label.style.top = dynamicTop;
|
2624 |
+
label.dataset.dynamicTop = dynamicTop;
|
2625 |
+
}
|
2626 |
+
label.dataset.positionClass = positionClass; // Store for collapse restoration
|
2627 |
|
2628 |
// Ensure the model name is always displayed
|
2629 |
const modelName = model.display_name || model.model_name || 'Unknown Model';
|
|
|
2667 |
<div class="timeline-date">${otherLabel.dataset.modelDate}</div>
|
2668 |
`;
|
2669 |
|
2670 |
+
// Restore dynamic positioning after content change
|
2671 |
setTimeout(() => {
|
2672 |
+
// Restore the dynamically calculated position
|
2673 |
+
const isAbove = otherLabel.dataset.positionClass && otherLabel.dataset.positionClass.includes('above');
|
2674 |
+
if (isAbove && otherLabel.dataset.dynamicBottom) {
|
2675 |
+
otherLabel.style.bottom = otherLabel.dataset.dynamicBottom;
|
2676 |
+
otherLabel.style.top = '';
|
2677 |
+
} else if (!isAbove && otherLabel.dataset.dynamicTop) {
|
2678 |
+
otherLabel.style.top = otherLabel.dataset.dynamicTop;
|
2679 |
+
otherLabel.style.bottom = '';
|
2680 |
+
}
|
2681 |
otherLabel.style.left = '';
|
2682 |
otherLabel.style.right = '';
|
2683 |
otherLabel.style.transform = 'translateX(-50%)';
|
|
|
2804 |
<div class="timeline-date">${label.dataset.modelDate}</div>
|
2805 |
`;
|
2806 |
|
2807 |
+
// Restore dynamic positioning after content change
|
2808 |
setTimeout(() => {
|
2809 |
+
// Restore the dynamically calculated position
|
2810 |
+
const isAbove = label.dataset.positionClass && label.dataset.positionClass.includes('above');
|
2811 |
+
if (isAbove && label.dataset.dynamicBottom) {
|
2812 |
+
label.style.bottom = label.dataset.dynamicBottom;
|
2813 |
+
label.style.top = '';
|
2814 |
+
} else if (!isAbove && label.dataset.dynamicTop) {
|
2815 |
+
label.style.top = label.dataset.dynamicTop;
|
2816 |
+
label.style.bottom = '';
|
2817 |
+
}
|
2818 |
label.style.left = '';
|
2819 |
label.style.right = '';
|
2820 |
// Reset transform: depends on current position
|
|
|
2968 |
// Check if the marker date falls between these two models
|
2969 |
// The marker should appear where the time period actually starts
|
2970 |
if (currentModelDate < currentDate && currentDate <= nextModelDate) {
|
2971 |
+
// Position the marker between these two models
|
2972 |
+
boundaryPosition = (i + 1) * spacing + 68;
|
|
|
|
|
|
|
2973 |
break;
|
2974 |
}
|
2975 |
}
|
|
|
2988 |
const position = boundaryPosition;
|
2989 |
|
2990 |
// Create marker only if it's within visible range and not too close to adjacent markers
|
2991 |
+
// Only check VS the last existing marker, since markers are added more recent each time.
|
2992 |
const existingMarkers = timeline.querySelectorAll('.date-marker');
|
2993 |
+
let shouldRemovePrevious = false;
|
2994 |
+
let lastMarker = null;
|
2995 |
+
let lastPos = null;
|
2996 |
+
|
2997 |
+
if (existingMarkers.length > 0) {
|
2998 |
+
lastMarker = existingMarkers[existingMarkers.length - 1];
|
2999 |
+
lastPos = parseFloat(lastMarker.style.left);
|
3000 |
+
if (Math.abs(position - lastPos) < 60) { // Minimum spacing between markers
|
3001 |
+
shouldRemovePrevious = true;
|
3002 |
}
|
3003 |
+
}
|
3004 |
|
3005 |
+
if (shouldRemovePrevious && lastMarker) {
|
3006 |
+
lastMarker.remove();
|
3007 |
+
// Also remove the label associated with that marker (next sibling in .date-label)
|
3008 |
+
const timelineLabels = timeline.querySelectorAll('.date-label');
|
3009 |
+
// Find the label with the left matching the previous marker
|
3010 |
+
for (let i = 0; i < timelineLabels.length; i++) {
|
3011 |
+
const lbl = timelineLabels[i];
|
3012 |
+
// label.style.left is like "123px"
|
3013 |
+
if (Math.abs(parseFloat(lbl.style.left) - (lastPos + 8)) < 2) { // allow for rounding errors
|
3014 |
+
lbl.remove();
|
3015 |
+
break;
|
3016 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3017 |
}
|
3018 |
+
}
|
3019 |
|
3020 |
+
// Create marker
|
3021 |
+
const marker = document.createElement('div');
|
3022 |
+
marker.className = `date-marker ${markerType}`;
|
3023 |
+
marker.style.left = position + 'px';
|
3024 |
+
|
3025 |
+
// Create vertical line (dashed)
|
3026 |
+
const line = document.createElement('div');
|
3027 |
+
line.style.position = 'absolute';
|
3028 |
+
line.style.top = '0px';
|
3029 |
+
line.style.bottom = '0px';
|
3030 |
+
line.style.left = '0px';
|
3031 |
+
line.style.width = '1px';
|
3032 |
+
line.style.borderLeft = '1px dashed #9ca3af';
|
3033 |
+
line.style.opacity = '0.5';
|
3034 |
+
line.style.zIndex = '0';
|
3035 |
+
if (markerType === 'year') {
|
3036 |
+
line.style.borderLeft = '1px dashed #6b7280';
|
3037 |
+
line.style.opacity = '0.7';
|
3038 |
}
|
3039 |
+
marker.appendChild(line);
|
3040 |
+
|
3041 |
+
// Create label (as a separate sibling, not a child)
|
3042 |
+
const label = document.createElement('div');
|
3043 |
+
label.className = 'date-label';
|
3044 |
+
label.textContent = format(currentDate);
|
3045 |
+
label.style.left = position + 8 + 'px'; // offset similar to CSS left: 8px for label
|
3046 |
+
|
3047 |
+
timeline.appendChild(marker);
|
3048 |
+
timeline.appendChild(label);
|
3049 |
|
3050 |
// Move to next marker
|
3051 |
currentDate.setMonth(currentDate.getMonth() + increment);
|
|
|
3329 |
"question-answering": "#c084fc",
|
3330 |
"fill-mask": "#d8b4fe",
|
3331 |
"text2text-generation": "#e879f9",
|
3332 |
+
"multiple-choice": "#c026d3",
|
3333 |
|
3334 |
"image-classification": "#06b6d4",
|
3335 |
"object-detection": "#0891b2",
|
|
|
3338 |
"instance-segmentation": "#164e63",
|
3339 |
"universal-segmentation": "#1e40af",
|
3340 |
"depth-estimation": "#1d4ed8",
|
3341 |
+
"masked-image-modeling": "#7c3aed",
|
3342 |
+
"causal-image-modeling": "#6d28d9",
|
3343 |
+
"keypoint-detection": "#4338ca",
|
3344 |
+
"keypoint-matching": "#3730a3",
|
3345 |
"zero-shot-image-classification": "#2563eb",
|
3346 |
"zero-shot-object-detection": "#3b82f6",
|
3347 |
"image-to-image": "#60a5fa",
|
|
|
3355 |
|
3356 |
"video-classification": "#dc2626",
|
3357 |
"audio-classification": "#ea580c",
|
3358 |
+
"audio-frame-classification": "#fb923c",
|
3359 |
+
"audio-xvector": "#fdba74",
|
3360 |
+
"automatic-speech-recognition": "#e11d48",
|
3361 |
+
"connectionist-temporal-classification": "#be123c",
|
3362 |
"text-to-audio": "#f97316",
|
3363 |
+
"text-to-waveform": "#fb923c",
|
3364 |
|
3365 |
"time-series-classification": "#84cc16",
|
3366 |
"time-series-regression": "#65a30d",
|
|
|
3403 |
checkbox.type = 'checkbox';
|
3404 |
checkbox.value = modality.key;
|
3405 |
checkbox.id = `modality-${modality.key}`;
|
3406 |
+
checkbox.checked = false; // All modalities unchecked by default
|
3407 |
|
3408 |
const label = document.createElement('label');
|
3409 |
label.htmlFor = `modality-${modality.key}`;
|
|
|
3422 |
loadTimeline();
|
3423 |
});
|
3424 |
|
3425 |
+
// Set initial state (unchecked, so no 'checked' class)
|
|
|
3426 |
|
3427 |
modalityFilters.appendChild(checkboxContainer);
|
3428 |
});
|
|
|
3432 |
}
|
3433 |
}
|
3434 |
|
3435 |
+
// Window resize handler - use efficient position update
|
3436 |
+
let resizeTimeout;
|
3437 |
window.addEventListener('resize', () => {
|
3438 |
+
// Update immediately for responsiveness
|
3439 |
+
updateCardPositions();
|
3440 |
+
|
3441 |
+
// Debounce full re-render for final adjustment
|
3442 |
+
clearTimeout(resizeTimeout);
|
3443 |
+
resizeTimeout = setTimeout(() => {
|
3444 |
+
if (currentModels.length > 0) {
|
3445 |
+
renderTimeline(currentModels, true);
|
3446 |
+
}
|
3447 |
+
}, 250);
|
3448 |
});
|
3449 |
|
3450 |
document.addEventListener('DOMContentLoaded', async () => {
|
|
|
3489 |
<div class="timeline-date">${label.dataset.modelDate}</div>
|
3490 |
`;
|
3491 |
|
3492 |
+
// Restore dynamic positioning after content change
|
3493 |
setTimeout(() => {
|
3494 |
+
// Restore the dynamically calculated position
|
3495 |
+
const isAbove = label.dataset.positionClass && label.dataset.positionClass.includes('above');
|
3496 |
+
if (isAbove && label.dataset.dynamicBottom) {
|
3497 |
+
label.style.bottom = label.dataset.dynamicBottom;
|
3498 |
+
label.style.top = '';
|
3499 |
+
} else if (!isAbove && label.dataset.dynamicTop) {
|
3500 |
+
label.style.top = label.dataset.dynamicTop;
|
3501 |
+
label.style.bottom = '';
|
3502 |
+
}
|
3503 |
label.style.transform = 'translateX(-50%)';
|
3504 |
label.parentElement.style.zIndex = '';
|
3505 |
}, 50);
|
|
|
3556 |
btn.textContent = '▸';
|
3557 |
localStorage.setItem('filtersCollapsed', 'true');
|
3558 |
}
|
3559 |
+
|
3560 |
+
// Update card positions immediately
|
3561 |
+
updateCardPositions();
|
3562 |
+
|
3563 |
+
// Continue updating during animation for smooth transition
|
3564 |
+
const startTime = performance.now();
|
3565 |
+
const animationDuration = 250; // Match CSS transition time
|
3566 |
+
|
3567 |
+
const animatePositions = (currentTime) => {
|
3568 |
+
const elapsed = currentTime - startTime;
|
3569 |
+
|
3570 |
+
if (elapsed < animationDuration) {
|
3571 |
+
updateCardPositions();
|
3572 |
+
requestAnimationFrame(animatePositions);
|
3573 |
+
} else {
|
3574 |
+
// Final update after animation completes
|
3575 |
+
updateCardPositions();
|
3576 |
+
}
|
3577 |
+
};
|
3578 |
+
|
3579 |
+
requestAnimationFrame(animatePositions);
|
3580 |
}
|
3581 |
</script>
|
3582 |
</body>
|