@@ -147,6 +153,18 @@ function initTimeline() {
`).join('');
+
+ // Add click handlers to steps for navigation
+ document.querySelectorAll('[data-step-index]').forEach(stepEl => {
+ stepEl.addEventListener('click', () => {
+ if (!isPlaying) {
+ const index = parseInt(stepEl.getAttribute('data-step-index'));
+ showStep(index);
+ document.getElementById('progress-info').classList.remove('hidden');
+ document.getElementById('service-status').classList.remove('hidden');
+ }
+ });
+ });
}
function getStepColor(type) {
@@ -172,10 +190,13 @@ async function playScenario() {
document.getElementById('start-btn').disabled = true;
document.getElementById('progress-info').classList.remove('hidden');
+ document.getElementById('service-status').classList.remove('hidden');
for (let i = 0; i <= steps.length - 1; i++) {
await showStep(i);
- await delay(2500); // 2.5 second delay between steps
+ if (i < steps.length - 1) {
+ await delay(speedDelays[playbackSpeed]);
+ }
}
isPlaying = false;
@@ -193,6 +214,13 @@ async function showStep(index) {
stepEl.classList.add('step-complete', 'border-green-500', 'bg-green-50');
}
+ // Mark future steps as pending
+ for (let i = index + 1; i < steps.length; i++) {
+ const stepEl = document.getElementById(`step-${i}`);
+ stepEl.className = 'border-2 border-gray-300 bg-white rounded-lg p-6 transition-all duration-300 cursor-pointer hover:shadow-lg';
+ stepEl.querySelector('.step-description').classList.add('hidden');
+ }
+
// Mark current step as active
const currentStepEl = document.getElementById(`step-${index}`);
currentStepEl.classList.add('step-active', 'border-blue-500', 'bg-blue-50', 'fade-in');
@@ -212,6 +240,34 @@ async function showStep(index) {
document.getElementById('progress-bar').style.width = `${progress}%`;
document.getElementById('progress-text').textContent = `${index + 1} / ${steps.length}`;
document.getElementById('current-step-desc').textContent = steps[index].description;
+
+ // Highlight active services
+ updateServiceStatus(index);
+}
+
+function updateServiceStatus(stepIndex) {
+ const instructionService = document.getElementById('service-instruction');
+ const validatorService = document.getElementById('service-validator');
+
+ // Reset both services to inactive
+ instructionService.classList.remove('opacity-100', 'bg-indigo-50', 'ring-2', 'ring-indigo-400');
+ instructionService.classList.add('opacity-30', 'bg-gray-50');
+ validatorService.classList.remove('opacity-100', 'bg-purple-50', 'ring-2', 'ring-purple-400');
+ validatorService.classList.add('opacity-30', 'bg-gray-50');
+
+ // Step 6: InstructionPersistence activates
+ if (stepIndex === 6) {
+ instructionService.classList.remove('opacity-30', 'bg-gray-50');
+ instructionService.classList.add('opacity-100', 'bg-indigo-50', 'ring-2', 'ring-indigo-400');
+ }
+
+ // Step 7: CrossReferenceValidator activates
+ if (stepIndex === 7) {
+ instructionService.classList.remove('opacity-30', 'bg-gray-50');
+ instructionService.classList.add('opacity-100', 'bg-indigo-50');
+ validatorService.classList.remove('opacity-30', 'bg-gray-50');
+ validatorService.classList.add('opacity-100', 'bg-purple-50', 'ring-2', 'ring-purple-400');
+ }
}
function resetScenario() {
@@ -221,7 +277,8 @@ function resetScenario() {
// Reset all steps
steps.forEach((_, index) => {
const stepEl = document.getElementById(`step-${index}`);
- stepEl.className = 'border-2 border-gray-300 bg-white rounded-lg p-6 transition-all duration-300';
+ stepEl.className = 'border-2 border-gray-300 bg-white rounded-lg p-6 transition-all duration-300 cursor-pointer hover:shadow-lg';
+ stepEl.setAttribute('data-step-index', index);
stepEl.querySelector('.step-description').classList.add('hidden');
});
@@ -229,17 +286,41 @@ function resetScenario() {
document.getElementById('progress-text').textContent = `0 / ${steps.length}`;
document.getElementById('current-step-desc').textContent = '';
document.getElementById('progress-info').classList.add('hidden');
+ document.getElementById('service-status').classList.add('hidden');
document.getElementById('start-btn').innerHTML = '▶ Start Scenario';
document.getElementById('start-btn').disabled = false;
+
+ // Reset services
+ updateServiceStatus(-1);
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
+// Speed control event listeners
+function setPlaybackSpeed(speed) {
+ playbackSpeed = speed;
+ document.querySelectorAll('.speed-btn').forEach(btn => {
+ if (btn.getAttribute('data-speed') === speed) {
+ btn.classList.remove('bg-gray-200', 'hover:bg-gray-300', 'text-gray-700');
+ btn.classList.add('bg-blue-600', 'text-white');
+ } else {
+ btn.classList.remove('bg-blue-600', 'text-white');
+ btn.classList.add('bg-gray-200', 'hover:bg-gray-300', 'text-gray-700');
+ }
+ });
+}
+
// Event listeners
document.getElementById('start-btn').addEventListener('click', playScenario);
document.getElementById('reset-btn').addEventListener('click', resetScenario);
+document.querySelectorAll('.speed-btn').forEach(btn => {
+ btn.addEventListener('click', () => {
+ setPlaybackSpeed(btn.getAttribute('data-speed'));
+ });
+});
+
// Initialize
initTimeline();