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
parent
6e38e24335
commit
ed3a43566c
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue