Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 0 additions & 55 deletions src/components/Breadcrumb.astro

This file was deleted.

210 changes: 0 additions & 210 deletions src/components/SectionSwitcher.astro

This file was deleted.

104 changes: 84 additions & 20 deletions src/components/Sidebar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,62 @@ function getIconPath(icon?: string): string {
return iconPaths[icon || 'default'] || iconPaths.default;
}

// ── Lifecycle-ordered product dropdown (Docs tab only) ──────────────────────
// Reorders the Docs section dropdown from alphabetical to agent-development-
// lifecycle order, grouped under lightweight phase headers. This is dropdown-only
// and does NOT reorder the `groups` array in navigation.ts, so the page list below
// still follows nav order. "Resources" is intentionally omitted; "Falcon AI" sits
// last; a "Reference" group links out to the Integrations/Guides/SDK/API tabs.
// The dropdown only renders when a tab exposes multiple groups (today that's the
// Docs tab); any other multi-group tab falls back to a single unlabelled list.
interface DropdownItem { title: string; icon: string; href: string; }
interface DropdownSection { phase: string; items: DropdownItem[]; }

const groupLookup = new Map(
allGroups.map(g => [g.group, { icon: g.icon || 'default', href: g.items[0]?.href || '/docs' }])
);
// Single source for turning a group title into a dropdown item.
const toItem = (title: string): DropdownItem => {
const g = groupLookup.get(title);
return { title, icon: g?.icon || 'default', href: g?.href || '/docs' };
};

const phasedOrder: { phase: string; titles: string[] }[] = [
{ phase: 'Start', titles: ['Get Started'] },
{ phase: 'Observe & diagnose', titles: ['Observability', 'Error Feed'] },
{ phase: 'Evaluate & measure', titles: ['Evaluation', 'Simulation', 'Dataset'] },
{ phase: 'Improve', titles: ['Optimization', 'Annotations'] },
{ phase: 'Build & connect', titles: ['Prompt', 'Prototype', 'Agent Playground', 'Knowledge Base', 'Agent Command Center'] },
{ phase: 'Protect', titles: ['Protect'] },
{ phase: 'Assistant', titles: ['Falcon AI'] },
];

// Reference links live in their own top-level tabs; surface them at the bottom.
const referenceItems: DropdownItem[] = [
{ title: 'Integrations', icon: 'plug', href: '/docs/integrations' },
{ title: 'Guides', icon: 'book', href: '/docs/cookbook' },
{ title: 'SDK Reference', icon: 'code', href: '/docs/sdk' },
{ title: 'API Reference', icon: 'webhook', href: '/docs/api' },
];

let dropdownSections: DropdownSection[];
if (isDocsTab) {
dropdownSections = phasedOrder
.map(p => ({ phase: p.phase, items: p.titles.filter(t => groupLookup.has(t)).map(toItem) }))
.filter(s => s.items.length > 0);

// Future-proofing: surface any Docs group not placed above (besides the hidden
// "Resources") under "More" so new products never silently vanish.
const placed = new Set<string>([...phasedOrder.flatMap(p => p.titles), 'Resources']);
const leftovers = allGroups.map(g => g.group).filter(t => !placed.has(t)).map(toItem);
if (leftovers.length) dropdownSections.push({ phase: 'More', items: leftovers });

dropdownSections.push({ phase: 'Reference', items: referenceItems });
} else {
// Other multi-group tabs: one unlabelled section (empty phase hides the header).
dropdownSections = [{ phase: '', items: allGroups.map(g => toItem(g.group)) }];
}

// Infer HTTP method from API endpoint title for sidebar badges
const isApiTab = activeTab?.tab === 'API';

Expand Down Expand Up @@ -139,26 +195,34 @@ function inferApiMethod(title: string): { method: string; css: string } | null {
class="absolute left-3 right-3 mt-1 py-1 bg-[var(--color-bg-secondary)] border border-[var(--color-border-default)] rounded-xl shadow-xl shadow-black/20 z-50 hidden opacity-0 transition-all duration-150 max-h-[60vh] overflow-y-auto hide-scrollbar"
data-section-dropdown
>
{allGroups.map((group) => {
const isCurrent = group.group === activeGroup?.group;
const firstHref = group.items[0]?.href || '/docs';
return (
<a
href={firstHref}
class:list={[
"flex items-center gap-2.5 px-3 py-2 mx-1 rounded-lg text-sm transition-colors",
isCurrent
? "bg-[var(--color-accent-primary)]/10 text-[var(--color-accent-primary)] font-medium"
: "text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-hover)]"
]}
>
<svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d={getIconPath(group.icon)} />
</svg>
<span class="flex-1 truncate">{group.group}</span>
</a>
);
})}
{dropdownSections.map((section, sectionIndex) => (
<div class:list={["px-1", sectionIndex > 0 && "mt-1.5 pt-1.5 border-t border-[var(--color-border-default)]/60"]}>
{section.phase && (
<div class="px-2 py-1">
<span class="text-[11px] font-semibold text-[var(--color-text-muted)] uppercase tracking-wider">{section.phase}</span>
</div>
)}
{section.items.map((item) => {
const isCurrent = item.title === activeGroup?.group;
return (
<a
href={item.href}
class:list={[
"flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-colors",
isCurrent
? "bg-[var(--color-accent-primary)]/10 text-[var(--color-accent-primary)] font-medium"
: "text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-bg-hover)]"
]}
>
<svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d={getIconPath(item.icon)} />
</svg>
<span class="flex-1 truncate">{item.title}</span>
</a>
);
})}
</div>
))}
</div>
</div>
)}
Expand Down
Loading