refactor(api): Remove deprecated api-tabs component
Remove unused tabs component and partials: - Delete assets/js/components/api-tabs.ts - Delete layouts/partials/api/tabs.html - Delete layouts/partials/api/tab-panels.html - Remove ApiTabs from main.js component registry The new architecture renders content directly without tabs.worktree-2025-12-30T19-16-55
parent
b1a05aaa64
commit
4c5d99d8cf
|
|
@ -1,144 +0,0 @@
|
|||
/**
|
||||
* API Tabs Component
|
||||
*
|
||||
* Handles tab switching for API reference documentation.
|
||||
* Uses data-tab and data-tab-panel attributes for explicit panel targeting,
|
||||
* unlike the generic tabs which use positional indexing.
|
||||
*
|
||||
* Features:
|
||||
* - Explicit panel targeting via data-tab-panel
|
||||
* - Deep linking via URL hash
|
||||
* - Browser back/forward navigation support
|
||||
* - Custom event dispatch for TOC updates
|
||||
*
|
||||
* Usage:
|
||||
* <div class="api-tabs-wrapper" data-component="api-tabs">
|
||||
* <div class="api-tabs-nav">
|
||||
* <a href="#operations" data-tab="operations" class="is-active">Operations</a>
|
||||
* <a href="#auth" data-tab="auth">Authentication</a>
|
||||
* </div>
|
||||
* </div>
|
||||
* <div class="api-tab-panels">
|
||||
* <section data-tab-panel="operations">...</section>
|
||||
* <section data-tab-panel="auth" style="display:none">...</section>
|
||||
* </div>
|
||||
*/
|
||||
|
||||
interface ComponentOptions {
|
||||
component: HTMLElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the panels container (sibling element after tabs)
|
||||
*/
|
||||
function findPanelsContainer(tabsWrapper: HTMLElement): HTMLElement | null {
|
||||
let sibling = tabsWrapper.nextElementSibling;
|
||||
while (sibling) {
|
||||
if (sibling.classList.contains('api-tab-panels')) {
|
||||
return sibling as HTMLElement;
|
||||
}
|
||||
sibling = sibling.nextElementSibling;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to a specific tab
|
||||
*/
|
||||
function switchTab(
|
||||
tabsWrapper: HTMLElement,
|
||||
panelsContainer: HTMLElement,
|
||||
tabId: string,
|
||||
updateHash = true
|
||||
): void {
|
||||
// Update active tab
|
||||
const tabs = tabsWrapper.querySelectorAll<HTMLAnchorElement>('[data-tab]');
|
||||
tabs.forEach((tab) => {
|
||||
if (tab.dataset.tab === tabId) {
|
||||
tab.classList.add('is-active');
|
||||
} else {
|
||||
tab.classList.remove('is-active');
|
||||
}
|
||||
});
|
||||
|
||||
// Update visible panel
|
||||
const panels =
|
||||
panelsContainer.querySelectorAll<HTMLElement>('[data-tab-panel]');
|
||||
panels.forEach((panel) => {
|
||||
if (panel.dataset.tabPanel === tabId) {
|
||||
panel.style.display = 'block';
|
||||
} else {
|
||||
panel.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Update URL hash without scrolling
|
||||
if (updateHash) {
|
||||
history.replaceState(null, '', '#' + tabId);
|
||||
}
|
||||
|
||||
// Dispatch custom event for TOC update
|
||||
document.dispatchEvent(
|
||||
new CustomEvent('api-tab-change', { detail: { tab: tabId } })
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tab ID from URL hash
|
||||
*/
|
||||
function getTabFromHash(): string | null {
|
||||
const hash = window.location.hash.substring(1);
|
||||
return hash || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize API Tabs component
|
||||
*/
|
||||
export default function ApiTabs({ component }: ComponentOptions): void {
|
||||
const panelsContainer = findPanelsContainer(component);
|
||||
|
||||
if (!panelsContainer) {
|
||||
console.warn('[API Tabs] No .api-tab-panels container found');
|
||||
return;
|
||||
}
|
||||
|
||||
const tabs = component.querySelectorAll<HTMLAnchorElement>('[data-tab]');
|
||||
|
||||
if (tabs.length === 0) {
|
||||
console.warn('[API Tabs] No tabs found with data-tab attribute');
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle tab clicks
|
||||
tabs.forEach((tab) => {
|
||||
tab.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation(); // Prevent other tab handlers from firing
|
||||
|
||||
const tabId = tab.dataset.tab;
|
||||
if (tabId) {
|
||||
switchTab(component, panelsContainer, tabId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle deep linking via URL hash on load
|
||||
const hashTab = getTabFromHash();
|
||||
if (hashTab) {
|
||||
const matchingTab = component.querySelector(`[data-tab="${hashTab}"]`);
|
||||
if (matchingTab) {
|
||||
switchTab(component, panelsContainer, hashTab, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle browser back/forward navigation
|
||||
window.addEventListener('hashchange', () => {
|
||||
const newTabId = getTabFromHash();
|
||||
if (newTabId) {
|
||||
const matchingTab = component.querySelector(`[data-tab="${newTabId}"]`);
|
||||
if (matchingTab) {
|
||||
switchTab(component, panelsContainer, newTabId, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -47,7 +47,6 @@ import { SidebarToggle } from './sidebar-toggle.js';
|
|||
import Theme from './theme.js';
|
||||
import ThemeSwitch from './theme-switch.js';
|
||||
import ApiRapiDoc from './components/api-rapidoc.ts';
|
||||
import ApiTabs from './components/api-tabs.ts';
|
||||
import ApiToc from './components/api-toc.ts';
|
||||
import RapiDocMini from './components/rapidoc-mini.ts';
|
||||
|
||||
|
|
@ -82,7 +81,6 @@ const componentRegistry = {
|
|||
theme: Theme,
|
||||
'theme-switch': ThemeSwitch,
|
||||
'api-rapidoc': ApiRapiDoc,
|
||||
'api-tabs': ApiTabs,
|
||||
'api-toc': ApiToc,
|
||||
'rapidoc-mini': RapiDocMini,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
{{/*
|
||||
API Reference Tab Panels (DEPRECATED)
|
||||
|
||||
This partial is kept for backward compatibility.
|
||||
The new architecture renders content directly in layouts:
|
||||
- layouts/api/list.html: Tag pages with operations list
|
||||
- layouts/api/single.html: Individual operation pages with RapiDoc
|
||||
|
||||
For conceptual pages (isConceptual: true), renders tag description content.
|
||||
For operational pages, renders the API documentation via RapiDoc.
|
||||
*/}}
|
||||
|
||||
{{ $isConceptual := .Params.isConceptual | default false }}
|
||||
|
||||
{{ if $isConceptual }}
|
||||
{{/* Conceptual Page - Display tag description content only */}}
|
||||
<section class="api-conceptual-content">
|
||||
{{ with .Content }}
|
||||
{{ . }}
|
||||
{{ else }}
|
||||
{{ with .Params.tagDescription }}
|
||||
{{ . | markdownify }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ else }}
|
||||
{{/* Operations Page - RapiDoc renderer */}}
|
||||
<section class="api-operations-panel">
|
||||
{{ partial "api/rapidoc.html" . }}
|
||||
</section>
|
||||
{{ end }}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{{/*
|
||||
API Reference Page Tabs (DEPRECATED)
|
||||
|
||||
This partial is kept for backward compatibility but renders nothing.
|
||||
The new architecture uses:
|
||||
- Tag pages (list.html): Display operations list directly
|
||||
- Operation pages (single.html): Display RapiDoc for single operation
|
||||
*/}}
|
||||
|
||||
{{/* No tabs rendered - using simplified layout */}}
|
||||
Loading…
Reference in New Issue