{# ================================================================================ Documentation Navigation Component (Kida-Native) ================================================================================ Hierarchical sidebar navigation for documentation sites. Uses pre-computed NavTree for optimal performance. KIDA FEATURES USED: - {% def %} for recursive macro (3x faster than {% include %}) - {% let %} for template-scoped variables - Optional chaining (?.) for null-safe access - Null coalescing (??) for smart defaults - {% match %} for node type dispatch - {% spaceless %} for clean HTML output FEATURES: - Hierarchical tree structure via NavTree API - Active page highlighting (automatic via NavNodeProxy) - Active trail marking (automatic via NavTreeContext) - Version-aware filtering (automatic via NavTreeCache) - Keyboard accessible - Section icons from frontmatter USAGE: {% include 'partials/docs-nav.html' %} ================================================================================ #} {# Control icon visibility - defaults to true if not passed in context #} {% let show_nav_icons = show_nav_icons ?? true %} {# ============================================================================= NAV NODE MACRO - Recursive navigation node renderer Replaces the previous docs-nav-node.html include pattern. Macros are compiled once and called as functions, eliminating the per-call overhead of {% include %} (context copy, template lookup). ============================================================================= #} {% def nav_node(item, depth=0, version_trigger=false) %} {# Extract values once with null-safe access #} {% let item_title = item?.title ?? 'Untitled' %} {% let item_icon = item?.icon ?? '' %} {% let item_href = item?.href ?? '' %} {% let item_children = item?.children ?? [] %} {% let item_status = item?.page?.metadata?.status ?? item?.page?.params?.status ?? '' %} {% let is_current = item?.is_current ?? false %} {% let is_in_trail = item?.is_in_trail ?? false %} {% let is_section = item?.is_section ?? false %} {% let has_children = item_children | length > 0 %} {% match has_children, depth %} {# ===== ROOT NODE (depth 0) - Static header, no toggle ===== #} {% case true, 0 %} {# Show the merged version switcher only on versioned, non-autodoc docs pages with more than one version — same guard the old version-selector used. When it does not hold, the root header renders exactly as before (byte-identical). #} {% let vs_show = version_trigger and versioning_enabled and versions | length > 1 and page?.version is not none and not (is_autodoc_page(page) if is_autodoc_page else false) %}
{% if vs_show %} {# ===== MERGED VERSION SWITCHER: the "Documentation" title IS the dropdown ===== Native
/ = the disclosure, so versions stay switchable with zero JS (each option is a real ); CSS rotates the caret via [open]; version-selector.js only adds close-on-outside-click + Esc + arrow keys. #} {# Resolve the pill label/status from page.version + the versions list. Do not read current_version.label: on section-index pages current_version arrives as an unresolved LazyValue and attribute access on it throws K-RUN-001 (dropping the page) or falls back to site.latest_version ("Latest" on older-version pages). The menu already matches by page.version. #} {% let cur_version_id = page?.version %} {% let vlabel = site.latest_version?.label ?? 'Latest' %} {% let vstatus = 'current' %} {% for v in versions %} {% if cur_version_id is not none and cur_version_id == v.id %} {% let vlabel = v.label %} {% let vstatus = v.status or (v.deprecated and 'deprecated' or 'legacy') %} {% end %} {% end %}
{% if show_nav_icons %} {% spaceless %} {{ icon(item_icon ?? 'book', size=16) }} {% end %} {% end %} {{ item_title }} {% if vlabel %} {{ vlabel }} {% end %}
{% else %} {# ===== Unchanged plain root header (non-versioned / autodoc / single version) ===== #}
{% if show_nav_icons %} {% spaceless %} {{ icon(item_icon ?? 'folder', size=16) }} {% end %} {% end %} {% if item_href %} {{ item_title }} {% else %} {{ item_title }} {% end %}
{% end %}
{% for child in item_children %} {{ nav_node(child, depth + 1) }} {% end %}
{# ===== EXPANDABLE NODE (depth > 0) - CSS-only accessible toggle ===== #} {# Uses
/ for native toggle + CSS :has() to control sibling visibility. The link is OUTSIDE (as a sibling), avoiding nested interactive elements. CSS Grid arranges: [toggle] [icon] [link] on first row, [items] spanning full width below. #} {% case true, _ %} {# ===== LEAF NODE (no children) ===== #} {% case false, _ %}
{% if item_href %} {% if show_nav_icons and is_section %} {% spaceless %} {{ icon(item_icon ?? 'folder', size=14) }} {% end %} {% end %} {{ item_title }} {% if item_status %} {{ item_status | capitalize }} {% end %} {% else %} {% if show_nav_icons and is_section %} {% spaceless %} {{ icon(item_icon ?? 'folder', size=14) }} {% end %} {% end %} {{ item_title }} {% end %}
{% end %} {% end %} {# ============================================================================= MAIN NAVIGATION COMPONENT ============================================================================= #} {# Check if page is autodoc - autodoc pages should use scoped navigation #} {% let is_autodoc = is_autodoc_page(page) if is_autodoc_page is defined else false %} {# Always scope docs navigation to the page's section root. The docs-nav template is only used by doc-type pages, so scoped navigation is the expected behavior - docs sidebar should show docs content only, not sibling top-level sections like releases or tracks. nav_root: true metadata can still be used to create navigation boundaries within a section (e.g., /api/python/ stops at itself, not /api/). #} {% let page_section = page?._section %} {% let root_section = page_section?.root ?? none %}