From e6e380f0a5df84e85623f26ef91d99eb1aafaa0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Thu, 19 Mar 2026 12:16:48 +0100 Subject: [PATCH] feat: add scrolling integrations banner to all doc pages - Add IntegrationsBanner component with infinite left-to-right CSS scroll animation showing all clients, integrations, and LLM providers - Place banner below the navbar on every page via Navbar theme wrapper - Add Agno and Hermes to both the IntegrationsGrid and the banner - Remove right border from doc sidebar via custom.css --- .../components/IntegrationsBanner.module.css | 82 +++++++++++++++++++ .../src/components/IntegrationsBanner.tsx | 80 ++++++++++++++++++ .../src/components/SupportedGrids.tsx | 2 + hindsight-docs/src/css/custom.css | 5 ++ hindsight-docs/src/theme/Navbar/index.tsx | 10 ++- 5 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 hindsight-docs/src/components/IntegrationsBanner.module.css create mode 100644 hindsight-docs/src/components/IntegrationsBanner.tsx diff --git a/hindsight-docs/src/components/IntegrationsBanner.module.css b/hindsight-docs/src/components/IntegrationsBanner.module.css new file mode 100644 index 000000000..16ef49ac5 --- /dev/null +++ b/hindsight-docs/src/components/IntegrationsBanner.module.css @@ -0,0 +1,82 @@ +.banner { + width: 100%; + overflow: hidden; + border-bottom: 1px solid var(--ifm-color-emphasis-200); + background: var(--ifm-background-surface-color); + padding: 7px 0; + /* Color cascades down to all items; dark mode is handled by Docusaurus on the html element */ + color: #555; + mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%); + -webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%); +} + +[data-theme='dark'] .banner { + color: #e0e0e0; + border-color: var(--ifm-color-emphasis-300); +} + +.track { + display: flex; + align-items: center; + white-space: nowrap; + width: max-content; + animation: scrollLeft 60s linear infinite; +} + +@keyframes scrollLeft { + from { transform: translateX(0); } + to { transform: translateX(-50%); } +} + +.itemLink { + text-decoration: none; + color: inherit; +} + +.itemLink:hover .item { + color: #0074d9; + border-color: #0074d9; + background: rgba(0, 116, 217, 0.08); +} + +[data-theme='dark'] .itemLink:hover .item { + color: #60aaff; + background: rgba(96, 170, 255, 0.12); + border-color: rgba(96, 170, 255, 0.5); +} + +.item { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 14px; + margin: 0 6px; + border-radius: 999px; + border: 1px solid var(--ifm-color-emphasis-300); + background: var(--ifm-background-color); + font-size: 0.78rem; + font-weight: 500; + color: inherit; + transition: color 0.15s, border-color 0.15s, background 0.15s; + user-select: none; +} + +[data-theme='dark'] .item { + border-color: var(--ifm-color-emphasis-400); + background: var(--ifm-background-surface-color); +} + +.itemIcon { + display: inline-flex; + align-items: center; + flex-shrink: 0; + opacity: 0.85; +} + +.itemIcon img { + display: block; +} + +.itemLabel { + line-height: 1; +} diff --git a/hindsight-docs/src/components/IntegrationsBanner.tsx b/hindsight-docs/src/components/IntegrationsBanner.tsx new file mode 100644 index 000000000..245b25fb0 --- /dev/null +++ b/hindsight-docs/src/components/IntegrationsBanner.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import type {IconType} from 'react-icons'; +import {SiPython, SiGo, SiOpenai, SiAnthropic, SiGooglegemini, SiOllama, SiVercel} from 'react-icons/si'; +import {LuTerminal, LuZap, LuBrainCog, LuSparkles, LuGlobe} from 'react-icons/lu'; +import styles from './IntegrationsBanner.module.css'; + +interface BannerItem { + label: string; + icon?: IconType; + imgSrc?: string; + href?: string; +} + +const OpenAICompatibleIcon: IconType = ({size = 18, ...props}) => ( + + + + + +); + +const ITEMS: BannerItem[] = [ + // Clients + {label: 'Python', icon: SiPython, href: '/sdks/python'}, + {label: 'TypeScript', imgSrc: '/img/icons/typescript.png', href: '/sdks/nodejs'}, + {label: 'Go', icon: SiGo, href: '/sdks/go'}, + {label: 'CLI', icon: LuTerminal, href: '/sdks/cli'}, + {label: 'HTTP', icon: LuGlobe, href: '/developer/api/quickstart'}, + // Integrations + {label: 'MCP Server', imgSrc: '/img/icons/mcp.png', href: '/sdks/integrations/local-mcp'}, + {label: 'LiteLLM', imgSrc: '/img/icons/litellm.png', href: '/sdks/integrations/litellm'}, + {label: 'OpenClaw', imgSrc: '/img/icons/openclaw.png', href: '/sdks/integrations/openclaw'}, + {label: 'Vercel AI', icon: SiVercel, href: '/sdks/integrations/ai-sdk'}, + {label: 'Vercel Chat', icon: SiVercel, href: '/sdks/integrations/chat'}, + {label: 'CrewAI', imgSrc: '/img/icons/crewai.png', href: '/sdks/integrations/crewai'}, + {label: 'Pydantic AI', imgSrc: '/img/icons/pydanticai.png', href: '/sdks/integrations/pydantic-ai'}, + {label: 'Skills', imgSrc: '/img/icons/skills.png', href: '/sdks/integrations/skills'}, + {label: 'Agno', imgSrc: '/img/icons/agno.png', href: '/sdks/integrations/agno'}, + {label: 'Hermes', imgSrc: '/img/icons/hermes.png', href: '/sdks/integrations/hermes'}, + // LLM Providers + {label: 'OpenAI', icon: SiOpenai}, + {label: 'Anthropic', icon: SiAnthropic}, + {label: 'Gemini', icon: SiGooglegemini}, + {label: 'Groq', icon: LuZap}, + {label: 'Ollama', icon: SiOllama}, + {label: 'LM Studio', icon: LuBrainCog}, + {label: 'MiniMax', icon: LuSparkles}, + {label: 'OpenAI Compat', icon: OpenAICompatibleIcon}, +]; + +function BannerItemComponent({item}: {item: BannerItem}) { + const content = ( + + + {item.icon && } + {item.imgSrc && {item.label}} + + {item.label} + + ); + return item.href + ? {content} + : {content}; +} + +export default function IntegrationsBanner(): JSX.Element { + const doubled = [...ITEMS, ...ITEMS]; + return ( +
+
+ {doubled.map((item, i) => ( + + ))} +
+
+ ); +} diff --git a/hindsight-docs/src/components/SupportedGrids.tsx b/hindsight-docs/src/components/SupportedGrids.tsx index 1c5aa2d7d..6d28cbea6 100644 --- a/hindsight-docs/src/components/SupportedGrids.tsx +++ b/hindsight-docs/src/components/SupportedGrids.tsx @@ -38,6 +38,8 @@ export function IntegrationsGrid() { { label: 'CrewAI', imgSrc: '/img/icons/crewai.png', href: '/sdks/integrations/crewai' }, { label: 'Pydantic AI', imgSrc: '/img/icons/pydanticai.png', href: '/sdks/integrations/pydantic-ai' }, { label: 'Skills', imgSrc: '/img/icons/skills.png', href: '/sdks/integrations/skills' }, + { label: 'Agno', imgSrc: '/img/icons/agno.png', href: '/sdks/integrations/agno' }, + { label: 'Hermes', imgSrc: '/img/icons/hermes.png', href: '/sdks/integrations/hermes' }, ]} /> ); } diff --git a/hindsight-docs/src/css/custom.css b/hindsight-docs/src/css/custom.css index 9537f0e67..fd5b4d2c1 100644 --- a/hindsight-docs/src/css/custom.css +++ b/hindsight-docs/src/css/custom.css @@ -1267,3 +1267,8 @@ html.docs-wrapper article h3 { } } + +/* Remove right border from doc sidebar */ +.theme-doc-sidebar-container { + border-right: none !important; +} diff --git a/hindsight-docs/src/theme/Navbar/index.tsx b/hindsight-docs/src/theme/Navbar/index.tsx index 48ce38adb..4509c6f39 100644 --- a/hindsight-docs/src/theme/Navbar/index.tsx +++ b/hindsight-docs/src/theme/Navbar/index.tsx @@ -1,11 +1,15 @@ import React, {type ReactNode} from 'react'; import NavbarLayout from '@theme/Navbar/Layout'; import NavbarContent from '@theme/Navbar/Content'; +import IntegrationsBanner from '@site/src/components/IntegrationsBanner'; export default function Navbar(): ReactNode { return ( - - - + <> + + + + + ); }