UI overhaul
This commit is contained in:
parent
0d22210040
commit
0adabad94d
@ -444,39 +444,46 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Smart Prompting Input Handling
|
||||
// Smart Prompting Input Handling - Fixed Race Conditions
|
||||
aiInput.addEventListener('input', () => {
|
||||
console.log('[DEBUG] Input event triggered, length:', aiInput.value.trim().length);
|
||||
const inputLength = aiInput.value.trim().length;
|
||||
|
||||
// Clear existing timeout
|
||||
// Clear ALL existing timeouts and abort controllers
|
||||
clearTimeout(enhancementTimeout);
|
||||
|
||||
// Cancel any pending enhancement call
|
||||
if (enhancementAbortController) {
|
||||
enhancementAbortController.abort();
|
||||
enhancementAbortController = null;
|
||||
}
|
||||
|
||||
// Hide suggestions if input is too short
|
||||
// Hide suggestions immediately if input is too short
|
||||
if (inputLength < 40) {
|
||||
showPromptingStatus('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show analyzing state after 1 second
|
||||
setTimeout(() => {
|
||||
if (aiInput.value.trim().length >= 50) {
|
||||
showPromptingStatus('analyzing');
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// Trigger AI enhancement after 1.5 seconds
|
||||
// Single consolidated timeout for all smart prompting logic
|
||||
enhancementTimeout = setTimeout(() => {
|
||||
console.log('[DEBUG] Enhancement timeout fired, calling triggerSmartPrompting');
|
||||
if (aiInput.value.trim().length >= 40) {
|
||||
triggerSmartPrompting();
|
||||
const currentLength = aiInput.value.trim().length;
|
||||
|
||||
// Double-check length hasn't changed during timeout
|
||||
if (currentLength < 40) {
|
||||
showPromptingStatus('hidden');
|
||||
return;
|
||||
}
|
||||
}, 1500);
|
||||
|
||||
// Show analyzing state first
|
||||
if (currentLength >= 50) {
|
||||
showPromptingStatus('analyzing');
|
||||
|
||||
// Trigger enhancement after showing analyzing state
|
||||
setTimeout(() => {
|
||||
if (aiInput.value.trim().length >= 50) {
|
||||
triggerSmartPrompting();
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}, 1000); // Single timeout instead of multiple
|
||||
});
|
||||
|
||||
aiInput.addEventListener('input', updateCharacterCount);
|
||||
|
@ -68,40 +68,59 @@ const displayedScenarios = scenarios.slice(0, maxDisplayed);
|
||||
<script define:vars={{ allScenarios: scenarios, maxDisplay: maxDisplayed }}>
|
||||
let showingAllScenarios = false;
|
||||
|
||||
// Apply scenario search using existing search functionality
|
||||
|
||||
window.applyScenarioSearch = function(scenarioId) {
|
||||
console.log(`Applying scenario search: ${scenarioId}`);
|
||||
|
||||
// Find the main search input (existing)
|
||||
const clickedChip = document.querySelector(`[data-scenario-id="${scenarioId}"]`);
|
||||
const mainSearchInput = document.getElementById('search-input');
|
||||
if (mainSearchInput) {
|
||||
// Use scenario ID as search term (it should match tool tags)
|
||||
mainSearchInput.value = scenarioId;
|
||||
|
||||
if (!mainSearchInput) return;
|
||||
|
||||
// Check if this scenario is already active (allow deselection)
|
||||
if (clickedChip && clickedChip.classList.contains('active')) {
|
||||
// Deselect: clear search and remove active state
|
||||
mainSearchInput.value = '';
|
||||
document.querySelectorAll('.suggestion-chip').forEach(chip => {
|
||||
chip.classList.remove('active');
|
||||
});
|
||||
|
||||
// Trigger existing search functionality
|
||||
// Clear the targeted search input too
|
||||
const targetedInput = document.getElementById('targeted-search-input');
|
||||
if (targetedInput) {
|
||||
targetedInput.value = '';
|
||||
}
|
||||
|
||||
// Trigger search to show all results
|
||||
const inputEvent = new Event('input', { bubbles: true });
|
||||
mainSearchInput.dispatchEvent(inputEvent);
|
||||
|
||||
// Switch to grid view
|
||||
const gridToggle = document.querySelector('.view-toggle[data-view="grid"]');
|
||||
if (gridToggle && !gridToggle.classList.contains('active')) {
|
||||
gridToggle.click();
|
||||
}
|
||||
|
||||
// Scroll to results
|
||||
setTimeout(() => {
|
||||
const toolsGrid = document.getElementById('tools-grid');
|
||||
if (toolsGrid) {
|
||||
toolsGrid.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}, 200);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply new search
|
||||
mainSearchInput.value = scenarioId;
|
||||
|
||||
// Trigger existing search functionality
|
||||
const inputEvent = new Event('input', { bubbles: true });
|
||||
mainSearchInput.dispatchEvent(inputEvent);
|
||||
|
||||
// Switch to grid view
|
||||
const gridToggle = document.querySelector('.view-toggle[data-view="grid"]');
|
||||
if (gridToggle && !gridToggle.classList.contains('active')) {
|
||||
gridToggle.click();
|
||||
}
|
||||
|
||||
// Visual feedback
|
||||
document.querySelectorAll('.suggestion-chip').forEach(chip => {
|
||||
chip.classList.remove('active');
|
||||
});
|
||||
document.querySelector(`[data-scenario-id="${scenarioId}"]`)?.classList.add('active');
|
||||
if (clickedChip) {
|
||||
clickedChip.classList.add('active');
|
||||
}
|
||||
|
||||
// Scroll to results with better positioning
|
||||
window.scrollToElementById('tools-grid');
|
||||
};
|
||||
|
||||
// Toggle showing all scenarios
|
||||
@ -149,18 +168,14 @@ const displayedScenarios = scenarios.slice(0, maxDisplayed);
|
||||
|
||||
targetedInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
// Switch to grid view and scroll to results
|
||||
const gridToggle = document.querySelector('.view-toggle[data-view="grid"]');
|
||||
if (gridToggle) {
|
||||
e.preventDefault();
|
||||
// Switch to grid view and scroll to results
|
||||
const gridToggle = document.querySelector('.view-toggle[data-view="grid"]');
|
||||
if (gridToggle) {
|
||||
gridToggle.click();
|
||||
setTimeout(() => {
|
||||
const toolsGrid = document.getElementById('tools-grid');
|
||||
if (toolsGrid) {
|
||||
toolsGrid.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
// Use consolidated scroll utility
|
||||
window.scrollToElementById('tools-grid');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -117,15 +117,24 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
window.toolsData = toolsData;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const domainSelect = document.getElementById('domain-select');
|
||||
const phaseButtons = document.querySelectorAll('.phase-button');
|
||||
const proprietaryCheckbox = document.getElementById('include-proprietary');
|
||||
const tagCloudItems = document.querySelectorAll('.tag-cloud-item');
|
||||
const tagCloud = document.getElementById('tag-cloud');
|
||||
const tagCloudToggle = document.getElementById('tag-cloud-toggle');
|
||||
const viewToggles = document.querySelectorAll('.view-toggle');
|
||||
const aiViewToggle = document.getElementById('ai-view-toggle');
|
||||
// Cache DOM elements once
|
||||
const elements = {
|
||||
searchInput: document.getElementById('search-input'),
|
||||
domainSelect: document.getElementById('domain-select'),
|
||||
phaseButtons: document.querySelectorAll('.phase-button'),
|
||||
proprietaryCheckbox: document.getElementById('include-proprietary'),
|
||||
tagCloudItems: document.querySelectorAll('.tag-cloud-item'),
|
||||
tagCloud: document.getElementById('tag-cloud'),
|
||||
tagCloudToggle: document.getElementById('tag-cloud-toggle'),
|
||||
viewToggles: document.querySelectorAll('.view-toggle'),
|
||||
aiViewToggle: document.getElementById('ai-view-toggle')
|
||||
};
|
||||
|
||||
// Verify critical elements exist
|
||||
if (!elements.searchInput || !elements.domainSelect || !elements.proprietaryCheckbox) {
|
||||
console.error('Critical filter elements not found');
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedTags = new Set();
|
||||
let selectedPhase = '';
|
||||
@ -133,7 +142,7 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
|
||||
function initTagCloud() {
|
||||
const visibleCount = 22;
|
||||
tagCloudItems.forEach((item, index) => {
|
||||
elements.tagCloudItems.forEach((item, index) => {
|
||||
if (index >= visibleCount) {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
@ -145,22 +154,22 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
const visibleCount = 22;
|
||||
|
||||
if (isTagCloudExpanded) {
|
||||
tagCloud.classList.add('expanded');
|
||||
tagCloudToggle.textContent = 'Weniger zeigen';
|
||||
tagCloudToggle.setAttribute('data-expanded', 'true');
|
||||
elements.tagCloud.classList.add('expanded');
|
||||
elements.tagCloudToggle.textContent = 'Weniger zeigen';
|
||||
elements.tagCloudToggle.setAttribute('data-expanded', 'true');
|
||||
|
||||
tagCloudItems.forEach(item => {
|
||||
elements.tagCloudItems.forEach(item => {
|
||||
if (!item.classList.contains('hidden')) {
|
||||
item.style.display = 'inline-flex';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
tagCloud.classList.remove('expanded');
|
||||
tagCloudToggle.textContent = 'Mehr zeigen';
|
||||
tagCloudToggle.setAttribute('data-expanded', 'false');
|
||||
elements.tagCloud.classList.remove('expanded');
|
||||
elements.tagCloudToggle.textContent = 'Mehr zeigen';
|
||||
elements.tagCloudToggle.setAttribute('data-expanded', 'false');
|
||||
|
||||
let visibleIndex = 0;
|
||||
tagCloudItems.forEach(item => {
|
||||
elements.tagCloudItems.forEach(item => {
|
||||
if (!item.classList.contains('hidden')) {
|
||||
if (visibleIndex < visibleCount) {
|
||||
item.style.display = 'inline-flex';
|
||||
@ -174,11 +183,11 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
}
|
||||
|
||||
function filterTagCloud() {
|
||||
const searchTerm = searchInput.value.toLowerCase();
|
||||
const searchTerm = elements.searchInput.value.toLowerCase();
|
||||
let visibleCount = 0;
|
||||
const maxVisibleWhenCollapsed = 22;
|
||||
|
||||
tagCloudItems.forEach(item => {
|
||||
elements.tagCloudItems.forEach(item => {
|
||||
const tagName = item.getAttribute('data-tag').toLowerCase();
|
||||
const shouldShow = tagName.includes(searchTerm);
|
||||
|
||||
@ -196,10 +205,10 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
}
|
||||
});
|
||||
|
||||
const hasHiddenTags = Array.from(tagCloudItems).some(item =>
|
||||
const hasHiddenTags = Array.from(elements.tagCloudItems).some(item =>
|
||||
!item.classList.contains('hidden') && item.style.display === 'none'
|
||||
);
|
||||
tagCloudToggle.style.display = hasHiddenTags ? 'block' : 'none';
|
||||
elements.tagCloudToggle.style.display = hasHiddenTags ? 'block' : 'none';
|
||||
}
|
||||
|
||||
function isToolHosted(tool) {
|
||||
@ -224,7 +233,7 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
el.classList.remove('highlight-row', 'highlight-column');
|
||||
});
|
||||
|
||||
const selectedDomain = domainSelect.value;
|
||||
const selectedDomain = elements.domainSelect.value;
|
||||
|
||||
if (selectedDomain) {
|
||||
const domainRow = matrixTable.querySelector(`tr[data-domain="${selectedDomain}"]`);
|
||||
@ -252,9 +261,9 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
}
|
||||
|
||||
function filterTools() {
|
||||
const searchTerm = searchInput.value.toLowerCase();
|
||||
const selectedDomain = domainSelect.value;
|
||||
const includeProprietary = proprietaryCheckbox.checked;
|
||||
const searchTerm = elements.searchInput.value.toLowerCase();
|
||||
const selectedDomain = elements.domainSelect.value;
|
||||
const includeProprietary = elements.proprietaryCheckbox.checked;
|
||||
|
||||
const filtered = window.toolsData.filter(tool => {
|
||||
const domains = tool.domains || [];
|
||||
@ -314,7 +323,7 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
selectedPhase = '';
|
||||
button.classList.remove('active');
|
||||
} else {
|
||||
phaseButtons.forEach(btn => btn.classList.remove('active'));
|
||||
elements.phaseButtons.forEach(btn => btn.classList.remove('active'));
|
||||
selectedPhase = phase;
|
||||
button.classList.add('active');
|
||||
}
|
||||
@ -323,7 +332,7 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
}
|
||||
|
||||
function handleViewToggle(view) {
|
||||
viewToggles.forEach(btn => {
|
||||
elements.viewToggles.forEach(btn => {
|
||||
btn.classList.toggle('active', btn.getAttribute('data-view') === view);
|
||||
});
|
||||
|
||||
@ -339,37 +348,38 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
|
||||
function clearTagFilters() {
|
||||
selectedTags.clear();
|
||||
tagCloudItems.forEach(item => item.classList.remove('active'));
|
||||
elements.tagCloudItems.forEach(item => item.classList.remove('active'));
|
||||
filterTools();
|
||||
}
|
||||
|
||||
function clearAllFilters() {
|
||||
searchInput.value = '';
|
||||
domainSelect.value = '';
|
||||
elements.searchInput.value = '';
|
||||
elements.domainSelect.value = '';
|
||||
selectedPhase = '';
|
||||
phaseButtons.forEach(btn => btn.classList.remove('active'));
|
||||
elements.phaseButtons.forEach(btn => btn.classList.remove('active'));
|
||||
clearTagFilters();
|
||||
filterTagCloud();
|
||||
}
|
||||
|
||||
searchInput.addEventListener('input', () => {
|
||||
// Event listeners using cached elements
|
||||
elements.searchInput.addEventListener('input', () => {
|
||||
filterTagCloud();
|
||||
filterTools();
|
||||
});
|
||||
|
||||
domainSelect.addEventListener('change', filterTools);
|
||||
proprietaryCheckbox.addEventListener('change', filterTools);
|
||||
tagCloudToggle.addEventListener('click', toggleTagCloud);
|
||||
elements.domainSelect.addEventListener('change', filterTools);
|
||||
elements.proprietaryCheckbox.addEventListener('change', filterTools);
|
||||
elements.tagCloudToggle.addEventListener('click', toggleTagCloud);
|
||||
|
||||
tagCloudItems.forEach(item => {
|
||||
elements.tagCloudItems.forEach(item => {
|
||||
item.addEventListener('click', () => handleTagClick(item));
|
||||
});
|
||||
|
||||
phaseButtons.forEach(btn => {
|
||||
elements.phaseButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => handlePhaseClick(btn));
|
||||
});
|
||||
|
||||
viewToggles.forEach(btn => {
|
||||
elements.viewToggles.forEach(btn => {
|
||||
btn.addEventListener('click', () => handleViewToggle(btn.getAttribute('data-view')));
|
||||
});
|
||||
|
||||
|
@ -672,6 +672,13 @@ domains.forEach((domain: any) => {
|
||||
const primaryModal = document.getElementById('tool-details-primary');
|
||||
const secondaryModal = document.getElementById('tool-details-secondary');
|
||||
|
||||
// Debounce rapid calls
|
||||
if (window.modalHideInProgress) return;
|
||||
window.modalHideInProgress = true;
|
||||
|
||||
setTimeout(() => {
|
||||
window.modalHideInProgress = false;
|
||||
}, 100);
|
||||
|
||||
if (modalType === 'both' || modalType === 'all') {
|
||||
if (primaryModal) {
|
||||
@ -702,13 +709,19 @@ domains.forEach((domain: any) => {
|
||||
if (contributeButtonSecondary) contributeButtonSecondary.style.display = 'none';
|
||||
}
|
||||
|
||||
// Consolidated state checking with safety checks
|
||||
const primaryActive = primaryModal && primaryModal.classList.contains('active');
|
||||
const secondaryActive = secondaryModal && secondaryModal.classList.contains('active');
|
||||
|
||||
// Update overlay and body classes atomically
|
||||
if (!primaryActive && !secondaryActive) {
|
||||
if (overlay) overlay.classList.remove('active');
|
||||
document.body.classList.remove('modals-side-by-side');
|
||||
} else if (primaryActive !== secondaryActive) {
|
||||
} else if (primaryActive && secondaryActive) {
|
||||
// Both active - ensure side-by-side class
|
||||
document.body.classList.add('modals-side-by-side');
|
||||
} else {
|
||||
// Only one active - remove side-by-side class
|
||||
document.body.classList.remove('modals-side-by-side');
|
||||
}
|
||||
};
|
||||
|
21
src/env.d.ts
vendored
21
src/env.d.ts
vendored
@ -22,10 +22,25 @@ declare global {
|
||||
findToolByIdentifier: (tools: any[], identifier: string) => any | undefined;
|
||||
isToolHosted: (tool: any) => boolean;
|
||||
|
||||
checkClientAuth: () => Promise<{authenticated: boolean; authRequired: boolean; expires?: string}>;
|
||||
requireClientAuth: (callback?: () => void, returnUrl?: string) => Promise<boolean>;
|
||||
showIfAuthenticated: (selector: string) => Promise<void>;
|
||||
checkClientAuth: (context?: string) => Promise<{authenticated: boolean; authRequired: boolean; expires?: string}>;
|
||||
requireClientAuth: (callback?: () => void, returnUrl?: string, context?: string) => Promise<boolean>;
|
||||
showIfAuthenticated: (selector: string, context?: string) => Promise<void>;
|
||||
setupAuthButtons: (selector?: string) => void;
|
||||
|
||||
// Consolidated scroll utilities
|
||||
scrollToElement: (element: Element | null, options?: ScrollIntoViewOptions) => void;
|
||||
scrollToElementById: (elementId: string, options?: ScrollIntoViewOptions) => void;
|
||||
scrollToElementBySelector: (selector: string, options?: ScrollIntoViewOptions) => void;
|
||||
|
||||
// Additional global functions that might be called
|
||||
applyScenarioSearch?: (scenarioId: string) => void;
|
||||
selectPhase?: (phase: string) => void;
|
||||
selectApproach?: (approach: string) => void;
|
||||
navigateToGrid?: (toolName: string) => void;
|
||||
navigateToMatrix?: (toolName: string) => void;
|
||||
toggleAllScenarios?: () => void;
|
||||
showShareDialog?: (shareButton: Element) => void;
|
||||
modalHideInProgress?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,35 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
|
||||
getStoredTheme
|
||||
};
|
||||
|
||||
// Consolidated scrolling utility
|
||||
(window as any).scrollToElement = function(element, options = {}) {
|
||||
if (!element) return;
|
||||
|
||||
// Calculate target position manually to avoid double-scroll
|
||||
setTimeout(() => {
|
||||
const headerHeight = document.querySelector('nav')?.offsetHeight || 80;
|
||||
const elementRect = element.getBoundingClientRect();
|
||||
const absoluteElementTop = elementRect.top + window.pageYOffset;
|
||||
const targetPosition = absoluteElementTop - headerHeight - 20; // Adjust this 20 as needed
|
||||
|
||||
window.scrollTo({
|
||||
top: targetPosition,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
// Convenience functions for common scroll targets
|
||||
(window as any).scrollToElementById = function(elementId, options = {}) {
|
||||
const element = document.getElementById(elementId);
|
||||
(window as any).scrollToElement(element, options);
|
||||
};
|
||||
|
||||
(window as any).scrollToElementBySelector = function(selector, options = {}) {
|
||||
const element = document.querySelector(selector);
|
||||
(window as any).scrollToElement(element, options);
|
||||
};
|
||||
|
||||
function createToolSlug(toolName) {
|
||||
if (!toolName || typeof toolName !== 'string') {
|
||||
console.warn('[toolHelpers] Invalid toolName provided to createToolSlug:', toolName);
|
||||
|
@ -192,14 +192,14 @@ const phases = data.phases;
|
||||
const methodologySection = document.getElementById('methodology-section');
|
||||
if (methodologySection) {
|
||||
methodologySection.classList.add('active');
|
||||
methodologySection.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
window.scrollToElementById('methodology-section');
|
||||
}
|
||||
} else if (approach === 'targeted') {
|
||||
// Show targeted scenarios section
|
||||
const targetedSection = document.getElementById('targeted-section');
|
||||
if (targetedSection) {
|
||||
targetedSection.classList.add('active');
|
||||
targetedSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
window.scrollToElementById('targeted-section');
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -213,13 +213,13 @@ const phases = data.phases;
|
||||
card.classList.remove('active');
|
||||
});
|
||||
|
||||
// Add active class to selected phase card (use actual phase ID)
|
||||
// Add active class to selected phase card
|
||||
const selectedCard = document.querySelector(`.phase-card.phase-${phase}`);
|
||||
if (selectedCard) {
|
||||
selectedCard.classList.add('active');
|
||||
}
|
||||
|
||||
// Use existing phase filter functionality with correct phase ID
|
||||
// Use existing phase filter functionality
|
||||
const existingPhaseButton = document.querySelector(`[data-phase="${phase}"]`);
|
||||
if (existingPhaseButton && !existingPhaseButton.classList.contains('active')) {
|
||||
existingPhaseButton.click();
|
||||
@ -231,13 +231,8 @@ const phases = data.phases;
|
||||
gridToggle.click();
|
||||
}
|
||||
|
||||
// Scroll to results after a short delay
|
||||
setTimeout(() => {
|
||||
const toolsGrid = document.getElementById('tools-grid');
|
||||
if (toolsGrid) {
|
||||
toolsGrid.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}, 300);
|
||||
// Scroll to results using consolidated utility
|
||||
window.scrollToElementById('tools-grid');
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
@ -367,7 +362,7 @@ const phases = data.phases;
|
||||
|
||||
if (targetCard) {
|
||||
console.log('Found target card, scrolling...');
|
||||
targetCard.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
window.scrollToElement(targetCard, { block: 'center' });
|
||||
targetCard.style.animation = 'highlight-flash 2s ease-out';
|
||||
|
||||
setTimeout(() => {
|
||||
@ -377,6 +372,8 @@ const phases = data.phases;
|
||||
}, 2000);
|
||||
} else {
|
||||
console.warn('Tool card not found in grid:', toolName);
|
||||
// Fallback to tools grid
|
||||
window.scrollToElementById('tools-grid');
|
||||
}
|
||||
}, 300);
|
||||
}, 200);
|
||||
@ -410,9 +407,11 @@ const phases = data.phases;
|
||||
|
||||
if (firstMatch) {
|
||||
console.log(`Found ${matchCount} occurrences of tool, highlighting all and scrolling to first`);
|
||||
firstMatch.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
window.scrollToElement(firstMatch, { block: 'center' });
|
||||
} else {
|
||||
console.warn('Tool chip not found in matrix:', toolName);
|
||||
// Fallback to matrix container
|
||||
window.scrollToElementById('matrix-container');
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user