|
| 1 | +# Shared Components Architecture |
| 2 | + |
| 3 | +This document explains how the shared Header and Footer components work across both the Docusaurus documentation site and standalone interactive applications. |
| 4 | + |
| 5 | +## 🎯 **Overview** |
| 6 | + |
| 7 | +The system uses a **dual-mode approach** where the same underlying configuration and components serve both: |
| 8 | +1. **Docusaurus Documentation Site** (`cortexjs.io`) |
| 9 | +2. **Standalone Interactive Apps** (`editor.mathlive.io`, `calculator.mathlive.io`, etc.) |
| 10 | + |
| 11 | +## 📁 **File Structure** |
| 12 | + |
| 13 | +``` |
| 14 | +src/ |
| 15 | +├── shared/ # Shared component library |
| 16 | +│ ├── components/ |
| 17 | +│ │ ├── Header.jsx # Standalone header component |
| 18 | +│ │ ├── Header.css # Unified styling |
| 19 | +│ │ ├── Footer.jsx # Standalone footer component |
| 20 | +│ │ ├── Footer.css # Footer styling |
| 21 | +│ │ └── index.js # Component exports |
| 22 | +│ ├── config/ |
| 23 | +│ │ └── navigation.json # Single source of truth for navigation |
| 24 | +│ ├── styles/ |
| 25 | +│ │ └── variables.css # Shared CSS variables |
| 26 | +│ └── utils/ |
| 27 | +│ └── docusaurus-config.js # Config converter for Docusaurus |
| 28 | +└── theme/ # Docusaurus theme overrides |
| 29 | + ├── Navbar/ |
| 30 | + │ └── index.js # Wraps Docusaurus navbar |
| 31 | + └── Footer/ |
| 32 | + └── index.js # Wraps Docusaurus footer |
| 33 | +``` |
| 34 | + |
| 35 | +## 🔄 **How It Works** |
| 36 | + |
| 37 | +### **1. Configuration Source** |
| 38 | + |
| 39 | +All navigation configuration comes from `src/shared/config/navigation.json`: |
| 40 | + |
| 41 | +```json |
| 42 | +{ |
| 43 | + "navbar": { |
| 44 | + "title": "MathLive", |
| 45 | + "items": [ |
| 46 | + { |
| 47 | + "type": "docSidebar", |
| 48 | + "sidebarId": "docSidebar", |
| 49 | + "label": "Mathfield" |
| 50 | + }, |
| 51 | + { |
| 52 | + "label": "Compute Engine", |
| 53 | + "href": "/compute-engine" |
| 54 | + }, |
| 55 | + { |
| 56 | + "type": "dropdown", |
| 57 | + "label": "Tools", |
| 58 | + "items": [ |
| 59 | + { "label": "LaTeX Editor", "href": "https://editor.mathlive.io" }, |
| 60 | + { "label": "Calculator", "href": "https://calculator.mathlive.io" } |
| 61 | + ] |
| 62 | + } |
| 63 | + ] |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +### **2. Docusaurus Integration** |
| 69 | + |
| 70 | +**Files involved:** |
| 71 | +- `src/theme/Navbar/index.js` - Theme override that wraps original navbar with `.shared-header` |
| 72 | +- `src/theme/Footer/index.js` - Theme override that wraps original footer with `.shared-footer` |
| 73 | +- `src/shared/utils/docusaurus-config.js` - Converts JSON config to Docusaurus format |
| 74 | +- `docusaurus.config.ts` - Uses `getDocusaurusNavbarConfig()` |
| 75 | + |
| 76 | +**Flow:** |
| 77 | +1. `docusaurus.config.ts` calls `getDocusaurusNavbarConfig()` |
| 78 | +2. Utility function reads `navigation.json` and converts to Docusaurus format |
| 79 | +3. Docusaurus renders its native navbar/footer with our config |
| 80 | +4. Theme overrides wrap with `.shared-header`/`.shared-footer` classes |
| 81 | +5. Shared CSS applies to both implementations |
| 82 | + |
| 83 | +### **3. Standalone Applications** |
| 84 | + |
| 85 | +**Files involved:** |
| 86 | +- `src/shared/components/Header.jsx` - Standalone header component |
| 87 | +- `src/shared/components/Footer.jsx` - Standalone footer component |
| 88 | + |
| 89 | +**Flow:** |
| 90 | +1. Components directly import and read `navigation.json` |
| 91 | +2. **Content filtering** happens based on `standalone` prop |
| 92 | +3. Components render using Docusaurus CSS classes |
| 93 | +4. Components wrap themselves with `.shared-header`/`.shared-footer` classes |
| 94 | +5. Same CSS applies as in Docusaurus case |
| 95 | + |
| 96 | +## 🎛️ **Content Filtering Logic** |
| 97 | + |
| 98 | +The standalone header modifies navigation content in three ways: |
| 99 | + |
| 100 | +### **1. Filter Out docSidebar Items** |
| 101 | +```javascript |
| 102 | +// In Header.jsx line 10-12 |
| 103 | +const filteredItems = standalone |
| 104 | + ? navbar.items.filter(item => item.type !== 'docSidebar') // Remove "Mathfield" |
| 105 | + : navbar.items; |
| 106 | +``` |
| 107 | + |
| 108 | +### **2. Add "Documentation" Link** |
| 109 | +```javascript |
| 110 | +// In Header.jsx lines 43-47 |
| 111 | +{standalone && ( |
| 112 | + <a href="/" className="navbar__item navbar__link"> |
| 113 | + Documentation |
| 114 | + </a> |
| 115 | +)} |
| 116 | +``` |
| 117 | + |
| 118 | +### **3. Convert docSidebar to Regular Links** |
| 119 | +```javascript |
| 120 | +// In Header.jsx lines 98-103 |
| 121 | +if (item.type === 'docSidebar' && standalone) { |
| 122 | + return ( |
| 123 | + <a href="/mathfield" className="navbar__item navbar__link"> |
| 124 | + {item.label} // Converts to regular link instead of sidebar trigger |
| 125 | + </a> |
| 126 | + ); |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +## 🎨 **Styling Strategy** |
| 131 | + |
| 132 | +### **Unified CSS Classes** |
| 133 | +Both Docusaurus and standalone components use **identical CSS classes**: |
| 134 | + |
| 135 | +**Header:** |
| 136 | +- `.navbar`, `.navbar__item`, `.navbar__link` |
| 137 | +- `.dropdown`, `.dropdown__menu`, `.dropdown__link` |
| 138 | +- `.navbar__brand`, `.navbar__logo` |
| 139 | + |
| 140 | +**Footer:** |
| 141 | +- `.footer`, `.footer--dark`, `.footer__links` |
| 142 | +- `.footer__title`, `.footer__link-item`, `.footer__copyright` |
| 143 | +- `.container`, `.row`, `.col` |
| 144 | + |
| 145 | +### **Styling Files** |
| 146 | +- `src/shared/styles/variables.css` - Shared CSS custom properties |
| 147 | +- `src/shared/components/Header.css` - Component-specific styles |
| 148 | +- `src/shared/components/Footer.css` - Footer styles |
| 149 | + |
| 150 | +### **Benefits** |
| 151 | +- ✅ **Visual Consistency**: Both implementations look identical |
| 152 | +- ✅ **Single Maintenance**: One set of styles to maintain |
| 153 | +- ✅ **Theme Compatibility**: Inherits Docusaurus dark mode, etc. |
| 154 | + |
| 155 | +## 📱 **Usage Examples** |
| 156 | + |
| 157 | +### **In Docusaurus** (Automatic) |
| 158 | +```javascript |
| 159 | +// docusaurus.config.ts |
| 160 | +navbar: getDocusaurusNavbarConfig(), |
| 161 | +footer: getDocusaurusFooterConfig(), |
| 162 | +``` |
| 163 | + |
| 164 | +### **In Standalone Apps** |
| 165 | +```javascript |
| 166 | +import { Header, Footer } from '../shared/components'; |
| 167 | + |
| 168 | +function App() { |
| 169 | + return ( |
| 170 | + <> |
| 171 | + <Header currentApp="editor" standalone={true} /> |
| 172 | + <main> |
| 173 | + {/* Your interactive app content */} |
| 174 | + </main> |
| 175 | + <Footer /> |
| 176 | + </> |
| 177 | + ); |
| 178 | +} |
| 179 | +``` |
| 180 | + |
| 181 | +## 🔧 **Development Workflow** |
| 182 | + |
| 183 | +### **Adding Navigation Items** |
| 184 | +1. Edit `src/shared/config/navigation.json` |
| 185 | +2. Changes automatically apply to both Docusaurus and standalone apps |
| 186 | +3. No code changes needed in most cases |
| 187 | + |
| 188 | +### **Styling Changes** |
| 189 | +1. Edit CSS files in `src/shared/components/` or `src/shared/styles/` |
| 190 | +2. Changes apply to both implementations |
| 191 | +3. Test using `/shared-components-preview` page |
| 192 | + |
| 193 | +### **Adding New Interactive Apps** |
| 194 | +1. Add entry to Tools dropdown in `navigation.json` |
| 195 | +2. Create new React app using shared components |
| 196 | +3. Deploy to appropriate subdomain |
| 197 | + |
| 198 | +## 🚀 **Deployment Strategy** |
| 199 | + |
| 200 | +### **Documentation Site** |
| 201 | +- Built with Docusaurus to `submodules/cortex-js.github.io/` |
| 202 | +- Deployed to GitHub Pages at `cortexjs.io` |
| 203 | + |
| 204 | +### **Interactive Apps** |
| 205 | +- Each app builds independently using shared components |
| 206 | +- Deploy to subdomains via Cloudflare routing: |
| 207 | + - `editor.mathlive.io` → `/apps/editor/` |
| 208 | + - `calculator.mathlive.io` → `/apps/calculator/` |
| 209 | + - etc. |
| 210 | + |
| 211 | +## 🐛 **Troubleshooting** |
| 212 | + |
| 213 | +### **"Cannot read properties of null" errors** |
| 214 | +- Usually caused by replacing Docusaurus navbar completely |
| 215 | +- Solution: Use wrapper approach in theme overrides |
| 216 | + |
| 217 | +### **Styling Inconsistencies** |
| 218 | +- Check that both implementations use same CSS classes |
| 219 | +- Verify shared variables are imported properly |
| 220 | + |
| 221 | +### **Navigation Not Updating** |
| 222 | +- Clear Docusaurus cache: `npm run clear` |
| 223 | +- Check `navigation.json` syntax |
| 224 | +- Verify `getDocusaurusNavbarConfig()` is called in config |
| 225 | + |
| 226 | +## 📈 **Future Enhancements** |
| 227 | + |
| 228 | +1. **Authentication Integration**: Add user login state to shared header |
| 229 | +2. **Dynamic Configuration**: Load navigation from API or CMS |
| 230 | +3. **Analytics Integration**: Track navigation usage across apps |
| 231 | +4. **A/B Testing**: Test different navigation structures |
| 232 | +5. **Internationalization**: Multi-language support for navigation |
0 commit comments