feat: enhance FAQ for Leader audience and improve navigation
**FAQ Enhancements:** - Added 6 new Leader-focused questions (TCO, board justification, liability, metrics, compliance) - Reordered all 28 questions to prioritize Leaders (IDs 1-18) - Added sorting by ID to ensure consistent order - Improved question categorization and keywords **UI Improvements:** - Enhanced search and filter functionality - Improved markdown rendering in FAQ answers - Better accessibility and keyboard navigation Leaders now see business-critical questions first, followed by technical implementation and research questions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f19154c9e6
commit
a754787555
4 changed files with 867 additions and 123 deletions
|
|
@ -22,10 +22,18 @@ class TractatusNavbar {
|
|||
|
||||
<!-- Left: Logo + Brand -->
|
||||
<div class="flex items-center">
|
||||
<a href="/" class="flex items-center space-x-3 hover:opacity-80 transition">
|
||||
<img src="/images/tractatus-icon.svg" alt="Tractatus Icon" class="w-8 h-8 text-blue-600">
|
||||
<span class="text-xl font-bold text-gray-900 hidden sm:inline">Tractatus Framework</span>
|
||||
<span class="text-xl font-bold text-gray-900 sm:hidden">Tractatus</span>
|
||||
<a href="/"
|
||||
class="flex items-center space-x-3 px-3 py-2 -ml-3 rounded-lg hover:bg-blue-50 transition-all duration-200 group"
|
||||
title="Return to homepage">
|
||||
<img src="/images/tractatus-icon.svg" alt="Tractatus Icon" class="w-8 h-8">
|
||||
<span class="text-xl font-bold text-gray-900 group-hover:text-blue-700 transition-colors hidden sm:inline">Tractatus Framework</span>
|
||||
<span class="text-xl font-bold text-gray-900 group-hover:text-blue-700 transition-colors sm:hidden">Tractatus</span>
|
||||
<svg class="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100 transition-opacity ml-1 hidden sm:block"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
@ -75,9 +83,6 @@ class TractatusNavbar {
|
|||
<a href="/docs.html" class="block px-3 py-2.5 text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">
|
||||
<span class="text-sm font-semibold">📚 Documentation</span>
|
||||
</a>
|
||||
<a href="/api-reference.html" class="block px-3 py-2.5 text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">
|
||||
<span class="text-sm font-semibold">🔌 API Reference</span>
|
||||
</a>
|
||||
<a href="/blog.html" class="block px-3 py-2.5 text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">
|
||||
<span class="text-sm font-semibold">📝 Blog</span>
|
||||
</a>
|
||||
|
|
@ -87,9 +92,6 @@ class TractatusNavbar {
|
|||
<a href="/about.html" class="block px-3 py-2.5 text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">
|
||||
<span class="text-sm font-semibold">ℹ️ About</span>
|
||||
</a>
|
||||
<a href="/demos/27027-demo.html" class="block px-3 py-2.5 text-gray-700 hover:bg-blue-50 hover:text-blue-700 rounded-lg transition">
|
||||
<span class="text-sm font-semibold">🎯 Interactive Demo</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -308,21 +308,45 @@ async function loadDocuments() {
|
|||
}
|
||||
});
|
||||
|
||||
// Auto-load first document in "Getting Started" category (order: 1)
|
||||
const gettingStartedDocs = grouped['getting-started'] || [];
|
||||
if (gettingStartedDocs.length > 0) {
|
||||
// Load the first document (order: 1) if available
|
||||
const firstDoc = gettingStartedDocs.find(d => d.order === 1);
|
||||
// Check for URL parameter to auto-expand category
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const categoryParam = urlParams.get('category');
|
||||
|
||||
// Auto-expand and navigate to category from URL parameter
|
||||
if (categoryParam && grouped[categoryParam] && grouped[categoryParam].length > 0) {
|
||||
// Expand the specified category
|
||||
const categoryDocsEl = listEl.querySelector(`.category-docs[data-category="${categoryParam}"]`);
|
||||
const categoryArrowEl = listEl.querySelector(`.category-toggle[data-category="${categoryParam}"] .category-arrow`);
|
||||
|
||||
if (categoryDocsEl) {
|
||||
categoryDocsEl.style.display = 'block';
|
||||
if (categoryArrowEl) {
|
||||
categoryArrowEl.style.transform = 'rotate(0deg)';
|
||||
}
|
||||
}
|
||||
|
||||
// Load first document in the category
|
||||
const firstDoc = grouped[categoryParam][0];
|
||||
if (firstDoc) {
|
||||
loadDocument(firstDoc.slug);
|
||||
} else {
|
||||
loadDocument(gettingStartedDocs[0].slug);
|
||||
}
|
||||
} else if (documents.length > 0) {
|
||||
// Fallback to first available document in any category
|
||||
const firstCategory = sortedCategories.find(([catId]) => grouped[catId] && grouped[catId].length > 0);
|
||||
if (firstCategory) {
|
||||
loadDocument(grouped[firstCategory[0]][0].slug);
|
||||
} else {
|
||||
// Default: Auto-load first document in "Getting Started" category (order: 1)
|
||||
const gettingStartedDocs = grouped['getting-started'] || [];
|
||||
if (gettingStartedDocs.length > 0) {
|
||||
// Load the first document (order: 1) if available
|
||||
const firstDoc = gettingStartedDocs.find(d => d.order === 1);
|
||||
if (firstDoc) {
|
||||
loadDocument(firstDoc.slug);
|
||||
} else {
|
||||
loadDocument(gettingStartedDocs[0].slug);
|
||||
}
|
||||
} else if (documents.length > 0) {
|
||||
// Fallback to first available document in any category
|
||||
const firstCategory = sortedCategories.find(([catId]) => grouped[catId] && grouped[catId].length > 0);
|
||||
if (firstCategory) {
|
||||
loadDocument(grouped[firstCategory[0]][0].slug);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,12 @@
|
|||
searchResultsSummary: null,
|
||||
searchResultsCount: null,
|
||||
searchHistoryContainer: null,
|
||||
searchHistory: null
|
||||
searchHistory: null,
|
||||
searchModal: null,
|
||||
openSearchModalBtn: null,
|
||||
searchModalCloseBtn: null,
|
||||
searchResultsModal: null,
|
||||
searchResultsListModal: null
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -66,10 +71,15 @@
|
|||
elements.searchResultsCount = document.getElementById('search-results-count');
|
||||
elements.searchHistoryContainer = document.getElementById('search-history-container');
|
||||
elements.searchHistory = document.getElementById('search-history');
|
||||
elements.searchModal = document.getElementById('search-modal');
|
||||
elements.openSearchModalBtn = document.getElementById('open-search-modal-btn');
|
||||
elements.searchModalCloseBtn = document.getElementById('search-modal-close-btn');
|
||||
elements.searchResultsModal = document.getElementById('search-results-modal');
|
||||
elements.searchResultsListModal = document.getElementById('search-results-list-modal');
|
||||
|
||||
// Check if elements exist
|
||||
if (!elements.searchInput) {
|
||||
console.warn('Search input not found - search enhancement disabled');
|
||||
// Check if essential elements exist
|
||||
if (!elements.searchInput || !elements.searchModal) {
|
||||
console.warn('Search elements not found - search enhancement disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +97,21 @@
|
|||
* Attach event listeners (CSP compliant - no inline handlers)
|
||||
*/
|
||||
function attachEventListeners() {
|
||||
// Search modal open/close
|
||||
if (elements.openSearchModalBtn) {
|
||||
elements.openSearchModalBtn.addEventListener('click', openSearchModal);
|
||||
}
|
||||
if (elements.searchModalCloseBtn) {
|
||||
elements.searchModalCloseBtn.addEventListener('click', closeSearchModal);
|
||||
}
|
||||
if (elements.searchModal) {
|
||||
elements.searchModal.addEventListener('click', function(e) {
|
||||
if (e.target === elements.searchModal) {
|
||||
closeSearchModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Search input - debounced
|
||||
if (elements.searchInput) {
|
||||
elements.searchInput.addEventListener('input', handleSearchInput);
|
||||
|
|
@ -132,10 +157,11 @@
|
|||
// Global keyboard shortcuts
|
||||
document.addEventListener('keydown', handleGlobalKeydown);
|
||||
|
||||
// Escape key to close modal
|
||||
// Escape key to close modals
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
closeSearchTipsModal();
|
||||
closeSearchModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -171,6 +197,7 @@
|
|||
}
|
||||
} else if (e.key === 'Escape') {
|
||||
closeSearchResultsPanel();
|
||||
closeSearchModal();
|
||||
e.target.blur();
|
||||
} else if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
|
|
@ -259,12 +286,18 @@
|
|||
* Render search results
|
||||
*/
|
||||
function renderSearchResults(data, duration) {
|
||||
if (!elements.searchResultsList || !elements.searchResultsPanel) return;
|
||||
// Use modal list if available, otherwise fall back to panel list
|
||||
const targetList = elements.searchResultsListModal || elements.searchResultsList;
|
||||
const targetContainer = elements.searchResultsModal || elements.searchResultsPanel;
|
||||
|
||||
if (!targetList) return;
|
||||
|
||||
const { documents, count, total, filters } = data;
|
||||
|
||||
// Show results panel
|
||||
elements.searchResultsPanel.classList.remove('hidden');
|
||||
// Show results container
|
||||
if (targetContainer) {
|
||||
targetContainer.classList.remove('hidden');
|
||||
}
|
||||
|
||||
// Update summary
|
||||
if (elements.searchResultsSummary && elements.searchResultsCount) {
|
||||
|
|
@ -289,7 +322,7 @@
|
|||
|
||||
// Render results
|
||||
if (documents.length === 0) {
|
||||
elements.searchResultsList.innerHTML = `
|
||||
targetList.innerHTML = `
|
||||
<div class="text-center py-8 text-gray-500">
|
||||
<svg class="w-12 h-12 mx-auto mb-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
|
||||
|
|
@ -339,7 +372,7 @@
|
|||
`;
|
||||
}).join('');
|
||||
|
||||
elements.searchResultsList.innerHTML = resultsHTML;
|
||||
targetList.innerHTML = resultsHTML;
|
||||
|
||||
// Attach click handlers to results
|
||||
document.querySelectorAll('.search-result-item').forEach(item => {
|
||||
|
|
@ -353,6 +386,7 @@
|
|||
if (slug && typeof loadDocument === 'function') {
|
||||
loadDocument(slug);
|
||||
closeSearchResultsPanel();
|
||||
closeSearchModal();
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
});
|
||||
|
|
@ -455,17 +489,54 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open search modal
|
||||
*/
|
||||
function openSearchModal() {
|
||||
if (elements.searchModal) {
|
||||
elements.searchModal.classList.remove('hidden');
|
||||
elements.searchModal.classList.add('show');
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
// Focus search input after modal opens
|
||||
setTimeout(() => {
|
||||
if (elements.searchInput) {
|
||||
elements.searchInput.focus();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close search modal
|
||||
*/
|
||||
function closeSearchModal() {
|
||||
if (elements.searchModal) {
|
||||
elements.searchModal.classList.remove('show');
|
||||
elements.searchModal.classList.add('hidden');
|
||||
document.body.style.overflow = '';
|
||||
|
||||
// Clear search when closing
|
||||
clearFilters();
|
||||
|
||||
// Hide results
|
||||
if (elements.searchResultsModal) {
|
||||
elements.searchResultsModal.classList.add('hidden');
|
||||
}
|
||||
if (elements.searchResultsSummary) {
|
||||
elements.searchResultsSummary.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle global keyboard shortcuts
|
||||
*/
|
||||
function handleGlobalKeydown(e) {
|
||||
// Ctrl+K or Cmd+K to focus search
|
||||
// Ctrl+K or Cmd+K to open search modal
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
if (elements.searchInput) {
|
||||
elements.searchInput.focus();
|
||||
elements.searchInput.select();
|
||||
}
|
||||
openSearchModal();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
819
public/js/faq.js
819
public/js/faq.js
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue