Last updated
Difficulty: General Owner: edujbarrios Writer: edujbarrios #components #templates #architecture

Template Components Architecture

NCMDS uses a modular component-based template system that separates concerns and makes the codebase more maintainable. Components are organized by file type for better clarity.

📂 Component Structure

All template components are located in templates/components/, organized by type:

templates/
├── layout.html              # Main layout (includes all components)
├── home.html                # Hero landing page
└── components/
    ├── html/                # HTML template components
    │   ├── head.html        # Meta tags, CSS, theme variables
    │   ├── header.html      # Site header with toggles
    │   ├── sidebar.html     # Navigation sidebar
    │   ├── toc.html         # Table of contents
    │   ├── doc_navigation.html  # Prev/Next buttons
    │   ├── footer.html      # Site footer
    │   ├── ai_chat.html     # AI chat widget
    │   ├── export_buttons.html  # QMD export button
    │   └── text_to_speech_button.html  # Read aloud button
    └── scripts/             # JavaScript components
        └── scripts.html     # JavaScript functionality

🧩 Component Details

HTML Components (components/html/)

head.html

Purpose: Document head configuration Includes: - Meta tags (charset, viewport, description, author) - Title tag - CSS links (main stylesheet, highlight.js) - Theme CSS variables (dark and light modes)

header.html

Purpose: Site header with navigation controls Includes: - Logo (SVG or image) - Site name - Theme toggle button (dark/light mode) - Sidebar toggle button (conditional) - TOC toggle button (conditional) - Mobile menu toggle

sidebar.html

Purpose: Documentation navigation Includes: - Sidebar title - Auto-generated navigation list - Empty state message - Active link highlighting

toc.html

Purpose: Table of contents for current document Includes: - TOC title - Generated TOC content (from Markdown headers) - Conditional rendering (only shows if TOC exists)

doc_navigation.html

Purpose: Previous/Next document navigation Includes: - Previous document button with title - Next document button with title - Spacers for missing prev/next - SVG icons for navigation

footer.html

Purpose: Site footer Includes: - Footer link groups (configurable in config.yaml) - Author link - Copyright information

ai_chat.html

Purpose: AI chat widget (Explain with AI) Includes: - Chat widget container with model selector - Message input and send button - Fullscreen toggle - Streaming response display - Configurable via ai_chat section in config.yaml

export_buttons.html

Purpose: QMD export button Includes: - Export to QMD button (visible in sidebar) - Conditional rendering based on export config - Downloads all documentation as a single QMD file

text_to_speech_button.html

Purpose: Read aloud button Includes: - Listen/Stop toggle button - Uses browser's Web Speech API - Configurable speech rate, pitch, and language - Position configurable via text_to_speech section in config.yaml

JavaScript Components (components/scripts/)

scripts.html

Purpose: All JavaScript functionality Includes: - Syntax highlighting initialization - Mobile menu toggle - Sidebar toggle with localStorage - TOC toggle with localStorage - Theme toggle with localStorage - Smooth scroll for anchor links - Active link highlighting - Copy button functionality for code blocks

🎯 Main Layout

The main layout.html file is extremely simple and clean:

<!DOCTYPE html>
<html lang="{{ config.html.language }}">
{% include 'components/html/head.html' %}
<body>
    {% include 'components/html/header.html' %}

    <div class="site-container">
        {% include 'components/html/sidebar.html' %}

        <main class="main-content">
            <div class="content-wrapper">
                {% if doc_last_updated %}
                <div class="doc-meta" aria-label="Document metadata">
                    <span class="doc-meta-label">Last updated</span>
                    <time class="doc-meta-value">{{ doc_last_updated }}</time>
                </div>
                {% endif %}

                {% if doc_tags or doc_difficulty or doc_owner or doc_writer %}
                <div class="doc-taxonomy" aria-label="Document metadata tags">
                    <!-- Difficulty, owner, writer chips and tag badges -->
                </div>
                {% endif %}

                <article class="markdown-body">
                    {{ content|safe }}
                </article>

                {% include 'components/html/doc_navigation.html' %}
            </div>
        </main>

        {% include 'components/html/toc.html' %}
    </div>

    {% include 'components/html/footer.html' %}
    {% include 'components/html/export_buttons.html' %}
    {% include 'components/html/text_to_speech_button.html' %}
    {% include 'components/html/ai_chat.html' %}
    {% include 'components/scripts/scripts.html' %}
</body>
</html>

✅ Benefits

Maintainability

  • Each component has a single responsibility
  • Easy to locate and modify specific functionality
  • Reduced file complexity

Reusability

  • Components can be included in multiple templates
  • Consistent UI across different pages
  • DRY (Don't Repeat Yourself) principle

Clarity

  • Clear separation of concerns
  • Self-documenting structure
  • Easy to understand for new contributors

Testing

  • Individual components can be tested in isolation
  • Easier to debug issues
  • Better error localization

🔧 Customization

Modifying a Component

To customize a specific part of the UI, simply edit the corresponding component file:

# Example: Customize the header
templates/components/html/header.html

Creating New Components

  1. Create a new .html file in the appropriate templates/components/ subdirectory:
  2. html/ for HTML template components
  3. scripts/ for JavaScript components
  4. Add your component code (HTML, Jinja2 templates)
  5. Include it in layout.html where needed:
{% include 'components/html/your_component.html' %}

Component Dependencies

Some components depend on: - Config variables: Passed from ncmds.py via Jinja2 context - CSS classes: Defined in modular CSS files under static/default_theme/ (imported by static/main.css) - JavaScript: In scripts.html for interactive components, plus static/ai_chat.js and static/search.js for dedicated features - External CSS: static/ai_chat.css for AI chat widget styling

🎨 Styling Components

Component styles are organized in modular CSS files under static/default_theme/. Each component typically has its own CSS file:

static/
├── main.css              # Entry point (imports all modules)
├── ai_chat.css           # AI chat widget styles
├── style.css             # Legacy stylesheet (backup)
└── default_theme/
    ├── base.css          # Reset & typography
    ├── header.css        # Header component styles
    ├── hero.css          # Hero section styles
    ├── sidebar.css       # Sidebar styles
    ├── toc.css           # Table of contents styles
    ├── content.css       # Main content & markdown
    ├── code.css          # Code blocks & syntax highlighting
    ├── navigation.css    # Navigation & footer
    ├── search.css        # Search functionality styles
    ├── responsive.css    # Media queries
    └── utilities.css     # Utility classes

Example CSS structure:

/* Header Component (in default_theme/header.css) */
.site-header { ... }
.header-container { ... }
.logo { ... }

/* Sidebar Component (in default_theme/sidebar.css) */
.sidebar { ... }
.sidebar-nav { ... }
.nav-list { ... }