This document summarizes the implementation of full-text search and table of contents features in Codex.
Controller (server/src/controllers/searchController.ts):
- Recursively searches all pages across all folders
- Case-insensitive matching
- Counts matches per page for relevance ranking
- Extracts contextual snippets (50 chars before/after match)
- Highlights matches with
<strong>tags - Returns sorted results (most matches first)
Route (server/src/routes/search.ts):
GET /api/search?q={query}- Search endpoint- Protected by authentication middleware
Response Format:
[
{
"path": "folder/page.md",
"title": "Page Title",
"snippet": "...context with <strong>match</strong>...",
"matches": 5
}
]Component (client/src/components/Search.tsx):
- Modal search interface with backdrop blur
- Keyboard shortcut:
⌘K/Ctrl+Kto open - 300ms debounced search for smooth typing
- Arrow key navigation (
↑↓) - Enter to select, Escape to close
- Outside click to dismiss
- Loading indicator during search
- Responsive result display with:
- Page title
- File path
- Match count badge
- Highlighted snippet
- Mouse hover updates selection
- Footer with keyboard hints
Styling (client/src/components/Search.css):
- Theme-aware (light/dark mode support)
- Fixed position modal overlay
- Smooth transitions and animations
- Scrollable results (max 400px height)
- Highlighted matches with accent colors
- Responsive (hides on screens < 1200px)
Integration:
- Added to App.tsx header alongside theme toggle
- New API method in
api.ts:search(query: string) - New type in
types/index.ts:SearchResultinterface - CSS variables for theming in App.css
Added comprehensive test suite in server/tests/api.test.ts:
- ✅ Search across all pages
- ✅ Correct result structure validation
- ✅ Match highlighting verification
- ✅ Relevance-based sorting
- ✅ Empty results for no matches
- ✅ Empty query handling
- ✅ Case-insensitive search
Test Results: All 7 search tests passing
Component (client/src/components/TableOfContents.tsx):
- Parses markdown headings from content
- Creates heading slugs matching rehype-slug format
- Intersection Observer for active section tracking
- localStorage persistence for collapsed state
- Smooth scroll to target sections
- Click handler for heading links
Heading Extraction:
- Regex:
/^(#{1,6})\s+(.+)$/ - Supports H1-H6 (level 1-6)
- Slug generation: lowercase, replace special chars with
-
Active Section Tracking:
- Uses Intersection Observer API
- Root margin:
-100px 0px -80% 0px - Highlights current section as user scrolls
- Auto-updates active heading in TOC
Styling (client/src/components/TableOfContents.css):
- Fixed position floating widget
- Right side of screen (20px from edge)
- Max width 280px, collapses to 48px
- Hierarchical indentation (12px per level)
- Smooth expand/collapse animations
- Custom scrollbar styling
- Active section highlighting with accent color
- Responsive: hides on screens < 1200px
Features:
- Toggle button to show/hide
- Collapsible state persists in localStorage
- Nested list structure for heading hierarchy
- Hover effects on links
- Active section indicator (border + background)
- Smooth scrolling to sections
Integration:
- Added to Preview.tsx at bottom
- Only renders when content exists
- Positioned above other page content (z-index: 100)
- Works with existing markdown rendering (rehypeSlug)
README.md additions:
- Added search and TOC to features list
- New section: "⌨️ Keyboard Shortcuts"
- New section: "🔍 Search Features" with usage guide
- New section: "📑 Table of Contents" with feature details
server/src/controllers/searchController.ts- Search logicserver/src/routes/search.ts- Search routeclient/src/components/Search.tsx- Search UIclient/src/components/Search.css- Search stylesclient/src/components/TableOfContents.tsx- TOC UIclient/src/components/TableOfContents.css- TOC stylesSEARCH_TOC.md- This document
server/src/index.ts- Registered search routeclient/src/services/api.ts- Added search methodclient/src/types/index.ts- Added SearchResult typeclient/src/App.tsx- Added Search component to headerclient/src/App.css- Added CSS variables for accents/hoversclient/src/components/Preview.tsx- Added TableOfContentsserver/tests/api.test.ts- Added search testsREADME.md- Documentation updates
- Server-side implementation (keeps client light)
- Recursive folder scanning efficient for personal wiki scale
- Caching already in place for page content (30s TTL)
- Debounced input (300ms) reduces server requests
- Returns only needed data (path, title, snippet, matches)
- Lightweight heading extraction (regex parse)
- Intersection Observer API (browser-native, efficient)
- Only renders when content exists
- Collapsed state reduces visual clutter
- Responsive hiding on small screens
- Search: All modern browsers (ES6+)
- Table of Contents: All browsers supporting Intersection Observer
- Chrome 51+
- Firefox 55+
- Safari 12.1+
- Edge 15+
- Search syntax (quotes, operators, filters)
- Recent searches history
- Search result pagination
- File type filtering
- Date range filtering
- Fuzzy matching
- Mini-map visualization
- Expandable/collapsible subsections
- Heading level filtering
- Print-friendly TOC
- Export TOC as list
Both features are now fully functional and tested. The search provides quick access to content across the entire knowledge base, while the table of contents enhances navigation within individual documents. Both features respect the existing dark mode theme and are optimized for keyboard-first workflows.