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:
TheFlow 2025-10-14 10:53:47 +13:00
parent f19154c9e6
commit a754787555
4 changed files with 867 additions and 123 deletions

View file

@ -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>

View file

@ -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) {

View file

@ -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();
}
}

File diff suppressed because it is too large Load diff