This document explains how the shared Header and Footer components work across both the Docusaurus documentation site and standalone interactive applications.
The system uses a dual-mode approach where the same underlying configuration and components serve both:
- Docusaurus Documentation Site (
cortexjs.io) - Standalone Interactive Apps (
editor.mathlive.io,calculator.mathlive.io, etc.)
src/
├── shared/ # Shared component library
│ ├── components/
│ │ ├── Header.jsx # Standalone header component
│ │ ├── Header.css # Unified styling
│ │ ├── Footer.jsx # Standalone footer component
│ │ ├── Footer.css # Footer styling
│ │ └── index.js # Component exports
│ ├── config/
│ │ └── navigation.json # Single source of truth for navigation
│ ├── styles/
│ │ └── variables.css # Shared CSS variables
│ └── utils/
│ └── docusaurus-config.js # Config converter for Docusaurus
└── theme/ # Docusaurus theme overrides
├── Navbar/
│ └── index.js # Wraps Docusaurus navbar
└── Footer/
└── index.js # Wraps Docusaurus footer
All navigation configuration comes from src/shared/config/navigation.json:
{
"navbar": {
"title": "MathLive",
"items": [
{
"type": "docSidebar",
"sidebarId": "docSidebar",
"label": "Mathfield"
},
{
"label": "Compute Engine",
"href": "/compute-engine"
},
{
"type": "dropdown",
"label": "Tools",
"items": [
{ "label": "LaTeX Editor", "href": "https://editor.mathlive.io" },
{ "label": "Calculator", "href": "https://calculator.mathlive.io" }
]
}
]
}
}Files involved:
src/theme/Navbar/index.js- Theme override that wraps original navbar with.shared-headersrc/theme/Footer/index.js- Theme override that wraps original footer with.shared-footersrc/shared/utils/docusaurus-config.js- Converts JSON config to Docusaurus formatdocusaurus.config.ts- UsesgetDocusaurusNavbarConfig()
Flow:
docusaurus.config.tscallsgetDocusaurusNavbarConfig()- Utility function reads
navigation.jsonand converts to Docusaurus format - Docusaurus renders its native navbar/footer with our config
- Theme overrides wrap with
.shared-header/.shared-footerclasses - Shared CSS applies to both implementations
Files involved:
src/shared/components/Header.jsx- Standalone header componentsrc/shared/components/Footer.jsx- Standalone footer component
Flow:
- Components directly import and read
navigation.json - Content filtering happens based on
standaloneprop - Components render using Docusaurus CSS classes
- Components wrap themselves with
.shared-header/.shared-footerclasses - Same CSS applies as in Docusaurus case
The standalone header modifies navigation content in three ways:
// In Header.jsx line 10-12
const filteredItems = standalone
? navbar.items.filter(item => item.type !== 'docSidebar') // Remove "Mathfield"
: navbar.items;// In Header.jsx lines 43-47
{standalone && (
<a href="/" className="navbar__item navbar__link">
Documentation
</a>
)}// In Header.jsx lines 98-103
if (item.type === 'docSidebar' && standalone) {
return (
<a href="/mathfield" className="navbar__item navbar__link">
{item.label} // Converts to regular link instead of sidebar trigger
</a>
);
}Both Docusaurus and standalone components use identical CSS classes:
Header:
.navbar,.navbar__item,.navbar__link.dropdown,.dropdown__menu,.dropdown__link.navbar__brand,.navbar__logo
Footer:
.footer,.footer--dark,.footer__links.footer__title,.footer__link-item,.footer__copyright.container,.row,.col
src/shared/styles/variables.css- Shared CSS custom propertiessrc/shared/components/Header.css- Component-specific stylessrc/shared/components/Footer.css- Footer styles
- ✅ Visual Consistency: Both implementations look identical
- ✅ Single Maintenance: One set of styles to maintain
- ✅ Theme Compatibility: Inherits Docusaurus dark mode, etc.
// docusaurus.config.ts
navbar: getDocusaurusNavbarConfig(),
footer: getDocusaurusFooterConfig(),import { Header, Footer } from '../shared/components';
function App() {
return (
<>
<Header currentApp="editor" standalone={true} />
<main>
{/* Your interactive app content */}
</main>
<Footer />
</>
);
}- Edit
src/shared/config/navigation.json - Changes automatically apply to both Docusaurus and standalone apps
- No code changes needed in most cases
- Edit CSS files in
src/shared/components/orsrc/shared/styles/ - Changes apply to both implementations
- Test using
/shared-components-previewpage
- Add entry to Tools dropdown in
navigation.json - Create new React app using shared components
- Deploy to appropriate subdomain
- Built with Docusaurus to
submodules/cortex-js.github.io/ - Deployed to GitHub Pages at
cortexjs.io
- Each app builds independently using shared components
- Deploy to subdomains via Cloudflare routing:
editor.mathlive.io→/apps/editor/calculator.mathlive.io→/apps/calculator/- etc.
- Usually caused by replacing Docusaurus navbar completely
- Solution: Use wrapper approach in theme overrides
- Check that both implementations use same CSS classes
- Verify shared variables are imported properly
- Clear Docusaurus cache:
npm run clear - Check
navigation.jsonsyntax - Verify
getDocusaurusNavbarConfig()is called in config
- Authentication Integration: Add user login state to shared header
- Dynamic Configuration: Load navigation from API or CMS
- Analytics Integration: Track navigation usage across apps
- A/B Testing: Test different navigation structures
- Internationalization: Multi-language support for navigation