refactor(api): Remove unused separate API nav code

Now that API navigation is integrated into Hugo's menu system:
- Remove api-nav.ts component (no longer needed)
- Remove api/sidebar-nav.html partial (replaced by api-menu-items.html)
- Remove api-nav component registration from main.js
- Update sidebar.html to pass siteData to nested-menu for API nav
- Fix anchor ID handling for special characters (like / in operation IDs)
worktree-2025-12-30T19-16-55
Jason Stirnaman 2025-12-09 16:07:48 -06:00
parent 6e38e24335
commit ed3a43566c
5 changed files with 21 additions and 357 deletions

View File

@ -1,76 +0,0 @@
/**
* API Navigation Component
*
* Handles collapsible navigation groups in the API sidebar.
* Features:
* - Toggle expand/collapse on group headers
* - ARIA accessibility support
* - Keyboard navigation
*
* Usage:
* <nav class="api-nav" data-component="api-nav">
* <div class="api-nav-group">
* <button class="api-nav-group-header" aria-expanded="false">
* Group Title
* </button>
* <ul class="api-nav-group-items">
* ...
* </ul>
* </div>
* </nav>
*/
interface ComponentOptions {
component: HTMLElement;
}
/**
* Initialize API Navigation component
*/
export default function ApiNav({ component }: ComponentOptions): void {
const headers = component.querySelectorAll<HTMLButtonElement>(
'.api-nav-group-header'
);
headers.forEach((header) => {
header.addEventListener('click', () => {
const isOpen = header.classList.toggle('is-open');
header.setAttribute('aria-expanded', String(isOpen));
const items = header.nextElementSibling;
if (items) {
items.classList.toggle('is-open', isOpen);
}
});
// Keyboard support - Enter and Space already work for buttons
// but add support for arrow keys to navigate between groups
header.addEventListener('keydown', (event: KeyboardEvent) => {
const allHeaders = Array.from(headers);
const currentIndex = allHeaders.indexOf(header);
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
if (currentIndex < allHeaders.length - 1) {
allHeaders[currentIndex + 1].focus();
}
break;
case 'ArrowUp':
event.preventDefault();
if (currentIndex > 0) {
allHeaders[currentIndex - 1].focus();
}
break;
case 'Home':
event.preventDefault();
allHeaders[0].focus();
break;
case 'End':
event.preventDefault();
allHeaders[allHeaders.length - 1].focus();
break;
}
});
});
}

View File

@ -122,21 +122,29 @@ function expandAccordions() {
// Expand accordions on load based on URL anchor
function openAccordionByHash() {
var anchor = window.location.hash;
var hash = window.location.hash;
if (!hash || hash.length <= 1) return;
// Use native DOM method to handle special characters in IDs (like /)
var id = hash.substring(1); // Remove leading #
var anchorElement = document.getElementById(id);
if (!anchorElement) return;
var $anchor = $(anchorElement);
function expandElement() {
if ($(anchor).parents('.expand').length > 0) {
return $(anchor).closest('.expand').children('.expand-label');
} else if ($(anchor).hasClass('expand')) {
return $(anchor).children('.expand-label');
if ($anchor.parents('.expand').length > 0) {
return $anchor.closest('.expand').children('.expand-label');
} else if ($anchor.hasClass('expand')) {
return $anchor.children('.expand-label');
}
return null;
}
if (expandElement() != null) {
if (expandElement().children('.expand-toggle').hasClass('open')) {
// Do nothing?
} else {
expandElement().children('.expand-toggle').trigger('click');
var $expandLabel = expandElement();
if ($expandLabel != null) {
if (!$expandLabel.children('.expand-toggle').hasClass('open')) {
$expandLabel.children('.expand-toggle').trigger('click');
}
}
}

View File

@ -46,7 +46,6 @@ import SidebarSearch from './components/sidebar-search.js';
import { SidebarToggle } from './sidebar-toggle.js';
import Theme from './theme.js';
import ThemeSwitch from './theme-switch.js';
import ApiNav from './components/api-nav.ts';
import ApiScalar from './components/api-scalar.ts';
import ApiTabs from './components/api-tabs.ts';
import ApiToc from './components/api-toc.ts';
@ -81,7 +80,6 @@ const componentRegistry = {
'sidebar-toggle': SidebarToggle,
theme: Theme,
'theme-switch': ThemeSwitch,
'api-nav': ApiNav,
'api-scalar': ApiScalar,
'api-tabs': ApiTabs,
'api-toc': ApiToc,

View File

@ -1,261 +0,0 @@
{{/*
API Reference Navigation for Sidebar
Displays a collapsible navigation tree for API endpoints,
organized by functional groups defined in data/api_nav_groups.yml.
Uses Hugo data from data/article-data/ to build navigation.
Supports both tag-based (new) and path-based (legacy) article data.
*/}}
{{/* Get product path data for data lookup */}}
{{ $productPathData := findRE "[^/]+.*?" .RelPermalink }}
{{ $product := index $productPathData 0 }}
{{ $version := index $productPathData 1 }}
{{/* Build data key for article data lookup */}}
{{/* Hugo converts hyphens to underscores in data file keys */}}
{{ $dataKey := "" }}
{{ if eq $product "influxdb3" }}
{{ $dataKey = print "influxdb3_" $version }}
{{ else if eq $product "influxdb" }}
{{ $dataKey = print $version }}
{{ else }}
{{ $dataKey = $product }}
{{ end }}
{{/* Get article data for this product */}}
{{/*
Hugo data path: data/article_data/influxdb/influxdb3_core/articles.yml
Access: .Site.Data.article_data.influxdb.influxdb3_core.articles.articles
The double "articles" is because:
- First "articles" is the filename (articles.yml)
- Second "articles" is the key inside the YAML file
*/}}
{{ $articles := slice }}
{{ with .Site.Data.article_data }}
{{ with index . "influxdb" }}
{{ with index . $dataKey }}
{{ with index . "articles" }}
{{ with index . "articles" }}
{{ $articles = . }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{/* Get navigation groups configuration */}}
{{ $navGroups := .Site.Data.api_nav_groups.groups }}
{{/* Check if articles use tag-based structure */}}
{{ $isTagBased := false }}
{{ if gt (len $articles) 0 }}
{{ $firstArticle := index $articles 0 }}
{{ if reflect.IsMap $firstArticle }}
{{ with index $firstArticle "fields" }}
{{ if reflect.IsMap . }}
{{ if isset . "tag" }}
{{ $isTagBased = true }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ if and (gt (len $articles) 0) $navGroups $isTagBased }}
{{/* Tag-based navigation */}}
<nav class="api-nav" data-component="api-nav">
<h4 class="api-nav-header">API Reference</h4>
{{/* Build a map of tag slug -> article for quick lookup */}}
{{ $articlesByTag := dict }}
{{ range $articles }}
{{ if and (reflect.IsMap .) (isset . "fields") }}
{{ $fields := index . "fields" }}
{{ if and (reflect.IsMap $fields) (isset $fields "tag") }}
{{ $tag := index $fields "tag" }}
{{ $articlesByTag = merge $articlesByTag (dict $tag .) }}
{{ end }}
{{ end }}
{{ end }}
{{/* Render navigation groups */}}
{{ range $groupIdx, $group := $navGroups }}
{{ $groupTags := $group.tags }}
{{ $groupHasArticles := false }}
{{/* Check if any tags in this group have articles */}}
{{ range $groupTags }}
{{ if index $articlesByTag . }}
{{ $groupHasArticles = true }}
{{ end }}
{{ end }}
{{ if $groupHasArticles }}
<div class="api-nav-group">
<button class="api-nav-group-header{{ if eq $groupIdx 0 }} is-open{{ end }}" aria-expanded="{{ if eq $groupIdx 0 }}true{{ else }}false{{ end }}">
{{ $group.name }}
</button>
<ul class="api-nav-group-items{{ if eq $groupIdx 0 }} is-open{{ end }}">
{{ range $groupTags }}
{{ $tagName := . }}
{{ $article := index $articlesByTag $tagName }}
{{ if $article }}
{{ $path := index $article "path" }}
{{ $fields := index $article "fields" }}
{{ $isConceptual := false }}
{{ if and (reflect.IsMap $fields) (isset $fields "isConceptual") }}
{{ $isConceptual = index $fields "isConceptual" }}
{{ end }}
{{/* Show operations from article data */}}
{{ $operations := slice }}
{{ if and (reflect.IsMap $fields) (isset $fields "operations") }}
{{ $operations = index $fields "operations" }}
{{ end }}
{{ if gt (len $operations) 0 }}
{{ range $operations }}
<li class="api-nav-item api-nav-operation">
<a href="{{ print "/" $product "/" $version "/" $path "/" | relURL }}#operation/{{ .operationId }}">
<span class="api-method api-method--{{ lower .method }}">{{ upper .method }}</span>
<code class="api-path">{{ .path }}</code>
</a>
</li>
{{ end }}
{{ else }}
{{/* Fallback for conceptual pages or pages without operations */}}
{{ $menuName := $tagName }}
{{ if and (reflect.IsMap $fields) (isset $fields "menuName") }}
{{ $menuName = index $fields "menuName" }}
{{ end }}
<li class="api-nav-item{{ if eq $.RelPermalink (print "/" $product "/" $version "/" $path "/") }} is-active{{ end }}{{ if $isConceptual }} is-conceptual{{ end }}">
<a href="{{ print "/" $product "/" $version "/" $path "/" | relURL }}">
{{ $menuName }}
</a>
</li>
{{ end }}
{{ end }}
{{ end }}
</ul>
</div>
{{ end }}
{{ end }}
</nav>
{{ else if gt (len $articles) 0 }}
{{/* Legacy path-based navigation (fallback) */}}
<nav class="api-nav" data-component="api-nav">
<h4 class="api-nav-header">API Reference</h4>
{{/* Group by API version (v3, v2, v1, or root) */}}
{{ $v3Endpoints := slice }}
{{ $v2Endpoints := slice }}
{{ $v1Endpoints := slice }}
{{ $rootEndpoints := slice }}
{{ range $idx, $article := $articles }}
{{ $articlePath := "" }}
{{ if and (reflect.IsMap $article) (isset $article "path") }}
{{ $articlePath = index $article "path" }}
{{ end }}
{{ if $articlePath }}
{{ if hasPrefix $articlePath "api/v3" }}
{{ $v3Endpoints = $v3Endpoints | append $article }}
{{ else if hasPrefix $articlePath "api/v2" }}
{{ $v2Endpoints = $v2Endpoints | append $article }}
{{ else if hasPrefix $articlePath "api/v1" }}
{{ $v1Endpoints = $v1Endpoints | append $article }}
{{ else }}
{{ $rootEndpoints = $rootEndpoints | append $article }}
{{ end }}
{{ end }}
{{ end }}
{{/* API v3 Endpoints */}}
{{ if gt (len $v3Endpoints) 0 }}
<div class="api-nav-group">
<button class="api-nav-group-header is-open" aria-expanded="true">
API v3
</button>
<ul class="api-nav-group-items is-open">
{{ range $v3Endpoints }}
{{ $path := index . "path" }}
{{ $menuName := $path }}
{{ if and (reflect.IsMap .) (isset . "fields") }}
{{ $fields := index . "fields" }}
{{ if and (reflect.IsMap $fields) (isset $fields "menuName") }}
{{ $menuName = index $fields "menuName" }}
{{ end }}
{{ end }}
<li class="api-nav-item{{ if eq $.RelPermalink (print "/" $product "/" $version "/" $path "/") }} is-active{{ end }}">
<a href="{{ print "/" $product "/" $version "/" $path "/" | relURL }}">
{{ $menuName }}
</a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
{{/* Server Management (root endpoints like /health, /metrics, /ping) */}}
{{ if gt (len $rootEndpoints) 0 }}
<div class="api-nav-group">
<button class="api-nav-group-header" aria-expanded="false">
Server Management
</button>
<ul class="api-nav-group-items">
{{ range $rootEndpoints }}
{{ $path := index . "path" }}
{{ $menuName := $path }}
{{ if and (reflect.IsMap .) (isset . "fields") }}
{{ $fields := index . "fields" }}
{{ if and (reflect.IsMap $fields) (isset $fields "menuName") }}
{{ $menuName = index $fields "menuName" }}
{{ end }}
{{ end }}
<li class="api-nav-item{{ if eq $.RelPermalink (print "/" $product "/" $version "/" $path "/") }} is-active{{ end }}">
<a href="{{ print "/" $product "/" $version "/" $path "/" | relURL }}">
{{ $menuName }}
</a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
{{/* Compatibility Endpoints (v1, v2) */}}
{{ $compatEndpoints := slice }}
{{ range $v1Endpoints }}
{{ $compatEndpoints = $compatEndpoints | append . }}
{{ end }}
{{ range $v2Endpoints }}
{{ $compatEndpoints = $compatEndpoints | append . }}
{{ end }}
{{ if gt (len $compatEndpoints) 0 }}
<div class="api-nav-group">
<button class="api-nav-group-header" aria-expanded="false">
Compatibility
</button>
<ul class="api-nav-group-items">
{{ range $compatEndpoints }}
{{ $path := index . "path" }}
{{ $menuName := $path }}
{{ if and (reflect.IsMap .) (isset . "fields") }}
{{ $fields := index . "fields" }}
{{ if and (reflect.IsMap $fields) (isset $fields "menuName") }}
{{ $menuName = index $fields "menuName" }}
{{ end }}
{{ end }}
<li class="api-nav-item{{ if eq $.RelPermalink (print "/" $product "/" $version "/" $path "/") }} is-active{{ end }}">
<a href="{{ print "/" $product "/" $version "/" $path "/" | relURL }}">
{{ $menuName }}
</a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
</nav>
{{ end }}

View File

@ -74,12 +74,12 @@
{{ $platformMenu := .Site.Menus.platform }}
<!-- Product Main Navigation -->
{{ partial "sidebar/nested-menu" (dict "page" $currentPage "menu" $mainMenu) . }}
{{ partial "sidebar/nested-menu" (dict "page" $currentPage "menu" $mainMenu "siteData" .Site.Data) }}
<!-- Product Reference Navigation -->
{{ if gt (len $refMenu) 0 }}
<h4 class="reference">Reference</h4>
{{ partial "sidebar/nested-menu" (dict "page" $currentPage "menu" $refMenu) . }}
{{ partial "sidebar/nested-menu" (dict "page" $currentPage "menu" $refMenu "siteData" .Site.Data) }}
{{ end }}
<!-- Flux links for InfluxDB docs -->
@ -97,7 +97,7 @@
{{ $platformWhitelist := `telegraf|chronograf|kapacitor|enterprise_influxdb|influxdb_1` }}
{{ if gt (len (findRE $platformWhitelist $menuKey)) 0 }}
<h4 class="platform">InfluxData Platform</h4>
{{ partial "sidebar/nested-menu" (dict "page" $currentPage "menu" $platformMenu) . }}
{{ partial "sidebar/nested-menu" (dict "page" $currentPage "menu" $platformMenu "siteData" .Site.Data) }}
{{ end }}
<!-- Additional resources for all docs -->
@ -110,9 +110,4 @@
{{ end }}
</ul>
{{/* API Reference Navigation - shown only for API pages */}}
{{ if eq .Type "api" }}
{{ partial "api/sidebar-nav.html" . }}
{{ end }}
</aside>