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
18e7a04bf6
commit
c8a7ed993b
4 changed files with 867 additions and 123 deletions
|
|
@ -22,10 +22,18 @@ class TractatusNavbar {
|
||||||
|
|
||||||
<!-- Left: Logo + Brand -->
|
<!-- Left: Logo + Brand -->
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<a href="/" class="flex items-center space-x-3 hover:opacity-80 transition">
|
<a href="/"
|
||||||
<img src="/images/tractatus-icon.svg" alt="Tractatus Icon" class="w-8 h-8 text-blue-600">
|
class="flex items-center space-x-3 px-3 py-2 -ml-3 rounded-lg hover:bg-blue-50 transition-all duration-200 group"
|
||||||
<span class="text-xl font-bold text-gray-900 hidden sm:inline">Tractatus Framework</span>
|
title="Return to homepage">
|
||||||
<span class="text-xl font-bold text-gray-900 sm:hidden">Tractatus</span>
|
<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>
|
</a>
|
||||||
</div>
|
</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">
|
<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>
|
<span class="text-sm font-semibold">📚 Documentation</span>
|
||||||
</a>
|
</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">
|
<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>
|
<span class="text-sm font-semibold">📝 Blog</span>
|
||||||
</a>
|
</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">
|
<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>
|
<span class="text-sm font-semibold">ℹ️ About</span>
|
||||||
</a>
|
</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>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -308,21 +308,45 @@ async function loadDocuments() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-load first document in "Getting Started" category (order: 1)
|
// Check for URL parameter to auto-expand category
|
||||||
const gettingStartedDocs = grouped['getting-started'] || [];
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
if (gettingStartedDocs.length > 0) {
|
const categoryParam = urlParams.get('category');
|
||||||
// Load the first document (order: 1) if available
|
|
||||||
const firstDoc = gettingStartedDocs.find(d => d.order === 1);
|
// 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) {
|
if (firstDoc) {
|
||||||
loadDocument(firstDoc.slug);
|
loadDocument(firstDoc.slug);
|
||||||
} else {
|
|
||||||
loadDocument(gettingStartedDocs[0].slug);
|
|
||||||
}
|
}
|
||||||
} else if (documents.length > 0) {
|
} else {
|
||||||
// Fallback to first available document in any category
|
// Default: Auto-load first document in "Getting Started" category (order: 1)
|
||||||
const firstCategory = sortedCategories.find(([catId]) => grouped[catId] && grouped[catId].length > 0);
|
const gettingStartedDocs = grouped['getting-started'] || [];
|
||||||
if (firstCategory) {
|
if (gettingStartedDocs.length > 0) {
|
||||||
loadDocument(grouped[firstCategory[0]][0].slug);
|
// 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) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,12 @@
|
||||||
searchResultsSummary: null,
|
searchResultsSummary: null,
|
||||||
searchResultsCount: null,
|
searchResultsCount: null,
|
||||||
searchHistoryContainer: 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.searchResultsCount = document.getElementById('search-results-count');
|
||||||
elements.searchHistoryContainer = document.getElementById('search-history-container');
|
elements.searchHistoryContainer = document.getElementById('search-history-container');
|
||||||
elements.searchHistory = document.getElementById('search-history');
|
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
|
// Check if essential elements exist
|
||||||
if (!elements.searchInput) {
|
if (!elements.searchInput || !elements.searchModal) {
|
||||||
console.warn('Search input not found - search enhancement disabled');
|
console.warn('Search elements not found - search enhancement disabled');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,6 +97,21 @@
|
||||||
* Attach event listeners (CSP compliant - no inline handlers)
|
* Attach event listeners (CSP compliant - no inline handlers)
|
||||||
*/
|
*/
|
||||||
function attachEventListeners() {
|
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
|
// Search input - debounced
|
||||||
if (elements.searchInput) {
|
if (elements.searchInput) {
|
||||||
elements.searchInput.addEventListener('input', handleSearchInput);
|
elements.searchInput.addEventListener('input', handleSearchInput);
|
||||||
|
|
@ -132,10 +157,11 @@
|
||||||
// Global keyboard shortcuts
|
// Global keyboard shortcuts
|
||||||
document.addEventListener('keydown', handleGlobalKeydown);
|
document.addEventListener('keydown', handleGlobalKeydown);
|
||||||
|
|
||||||
// Escape key to close modal
|
// Escape key to close modals
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener('keydown', function(e) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
closeSearchTipsModal();
|
closeSearchTipsModal();
|
||||||
|
closeSearchModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +197,7 @@
|
||||||
}
|
}
|
||||||
} else if (e.key === 'Escape') {
|
} else if (e.key === 'Escape') {
|
||||||
closeSearchResultsPanel();
|
closeSearchResultsPanel();
|
||||||
|
closeSearchModal();
|
||||||
e.target.blur();
|
e.target.blur();
|
||||||
} else if (e.key === 'ArrowDown') {
|
} else if (e.key === 'ArrowDown') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -259,12 +286,18 @@
|
||||||
* Render search results
|
* Render search results
|
||||||
*/
|
*/
|
||||||
function renderSearchResults(data, duration) {
|
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;
|
const { documents, count, total, filters } = data;
|
||||||
|
|
||||||
// Show results panel
|
// Show results container
|
||||||
elements.searchResultsPanel.classList.remove('hidden');
|
if (targetContainer) {
|
||||||
|
targetContainer.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
// Update summary
|
// Update summary
|
||||||
if (elements.searchResultsSummary && elements.searchResultsCount) {
|
if (elements.searchResultsSummary && elements.searchResultsCount) {
|
||||||
|
|
@ -289,7 +322,7 @@
|
||||||
|
|
||||||
// Render results
|
// Render results
|
||||||
if (documents.length === 0) {
|
if (documents.length === 0) {
|
||||||
elements.searchResultsList.innerHTML = `
|
targetList.innerHTML = `
|
||||||
<div class="text-center py-8 text-gray-500">
|
<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">
|
<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"/>
|
<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('');
|
}).join('');
|
||||||
|
|
||||||
elements.searchResultsList.innerHTML = resultsHTML;
|
targetList.innerHTML = resultsHTML;
|
||||||
|
|
||||||
// Attach click handlers to results
|
// Attach click handlers to results
|
||||||
document.querySelectorAll('.search-result-item').forEach(item => {
|
document.querySelectorAll('.search-result-item').forEach(item => {
|
||||||
|
|
@ -353,6 +386,7 @@
|
||||||
if (slug && typeof loadDocument === 'function') {
|
if (slug && typeof loadDocument === 'function') {
|
||||||
loadDocument(slug);
|
loadDocument(slug);
|
||||||
closeSearchResultsPanel();
|
closeSearchResultsPanel();
|
||||||
|
closeSearchModal();
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
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
|
* Handle global keyboard shortcuts
|
||||||
*/
|
*/
|
||||||
function handleGlobalKeydown(e) {
|
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') {
|
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (elements.searchInput) {
|
openSearchModal();
|
||||||
elements.searchInput.focus();
|
|
||||||
elements.searchInput.select();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
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