feat: add scrolling integrations banner to all doc pages (#616)
- 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
This commit is contained in:
parent
a56cd044e5
commit
fe12be47a0
5 changed files with 176 additions and 3 deletions
82
hindsight-docs/src/components/IntegrationsBanner.module.css
Normal file
82
hindsight-docs/src/components/IntegrationsBanner.module.css
Normal file
|
|
@ -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;
|
||||
}
|
||||
80
hindsight-docs/src/components/IntegrationsBanner.tsx
Normal file
80
hindsight-docs/src/components/IntegrationsBanner.tsx
Normal file
|
|
@ -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}) => (
|
||||
<span style={{position: 'relative', display: 'inline-flex'}}>
|
||||
<SiOpenai size={size} {...props} />
|
||||
<span style={{
|
||||
position: 'absolute', bottom: -2, right: -5,
|
||||
fontSize: Math.round((size as number) * 0.5), fontWeight: 900, lineHeight: 1,
|
||||
color: 'currentColor',
|
||||
}}>+</span>
|
||||
</span>
|
||||
);
|
||||
|
||||
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 = (
|
||||
<span className={styles.item}>
|
||||
<span className={styles.itemIcon}>
|
||||
{item.icon && <item.icon size={18} />}
|
||||
{item.imgSrc && <img src={item.imgSrc} alt={item.label} width={18} height={18} style={{objectFit: 'contain'}} />}
|
||||
</span>
|
||||
<span className={styles.itemLabel}>{item.label}</span>
|
||||
</span>
|
||||
);
|
||||
return item.href
|
||||
? <a href={item.href} className={styles.itemLink}>{content}</a>
|
||||
: <span>{content}</span>;
|
||||
}
|
||||
|
||||
export default function IntegrationsBanner(): JSX.Element {
|
||||
const doubled = [...ITEMS, ...ITEMS];
|
||||
return (
|
||||
<div className={styles.banner}>
|
||||
<div className={styles.track}>
|
||||
{doubled.map((item, i) => (
|
||||
<BannerItemComponent key={`${item.label}-${i}`} item={item} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -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' },
|
||||
]} />
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1267,3 +1267,8 @@ html.docs-wrapper article h3 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Remove right border from doc sidebar */
|
||||
.theme-doc-sidebar-container {
|
||||
border-right: none !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<NavbarLayout>
|
||||
<NavbarContent />
|
||||
</NavbarLayout>
|
||||
<>
|
||||
<NavbarLayout>
|
||||
<NavbarContent />
|
||||
</NavbarLayout>
|
||||
<IntegrationsBanner />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue