feat(docs): Integrations Hub + unified page hero (#620)
* fix(security): address all Dependabot vulnerability alerts Python (uv.lock, pyproject.toml): - authlib 1.6.6 → 1.6.9 (JWS header injection, OIDC hash binding, Bleichenbacher padding oracle) - pyasn1 0.6.2 → 0.6.3 (unbounded recursion DoS) - pyjwt 2.10.1 → 2.12.1 (unknown crit header extensions - also in integration-tests and crewai) - orjson 3.11.4 → 3.11.7 (deeply nested JSON recursion DoS) - tornado 6.5.2 → 6.5.5 (multipart DoS, incomplete cookie validation) npm (package.json, package-lock.json): - next ^16.1.6 → ^16.1.7 (HTTP smuggling, CSRF bypass, cache DoS, null origin bypass) - fast-xml-parser override updated to >=5.5.6 (numeric entity expansion bypass) - undici override added >=7.24.0 (WebSocket overflow, smuggling, CRLF injection, DoS) - flatted override added >=3.4.0 (unbounded recursion DoS) - svgo override added >=3.3.3 (DOCTYPE entity expansion DoS) - dompurify override added >=3.3.2 (XSS vulnerability) * feat(docs): add Integrations Hub and unified page hero - Add /integrations page with search, type filter, and card grid - Integrations defined in a single JSON file (src/data/integrations.json) supporting official and community entries with icon, author, and link - Scrolling integrations banner moved from global navbar to /integrations only - Remove IntegrationsGrid component; replace all usages with link to hub - Add PageHero component with full-bleed gradient background, shared across Cookbook, FAQ, Best Practices, Changelog, and Blog index pages - Remove FAQ from top navbar (already in Resources dropdown) - Move integration changelogs table to bottom of changelog page
This commit is contained in:
parent
ea662d062e
commit
80b1badf74
18 changed files with 787 additions and 106 deletions
|
|
@ -9,7 +9,7 @@ Get up and running with Hindsight in 60 seconds.
|
|||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeSnippet from '@site/src/components/CodeSnippet';
|
||||
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
|
||||
import {ClientsGrid} from '@site/src/components/SupportedGrids';
|
||||
|
||||
{/* Import raw source files */}
|
||||
import quickstartPy from '!!raw-loader!@site/examples/api/quickstart.py';
|
||||
|
|
@ -117,7 +117,7 @@ go get github.com/vectorize-io/hindsight/hindsight-clients/go
|
|||
|
||||
## Integrations
|
||||
|
||||
<IntegrationsGrid />
|
||||
Browse all supported integrations in the [Integrations Hub](/integrations).
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ sidebar_position: 1
|
|||
slug: /
|
||||
---
|
||||
|
||||
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
|
||||
import {ClientsGrid} from '@site/src/components/SupportedGrids';
|
||||
|
||||
# Overview
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ These settings only affect the `reflect` operation, not `recall`.
|
|||
|
||||
## Integrations
|
||||
|
||||
<IntegrationsGrid />
|
||||
Browse all supported integrations in the [Integrations Hub](/integrations).
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
|
|
|||
|
|
@ -209,10 +209,10 @@ const config: Config = {
|
|||
className: 'navbar-item-developer',
|
||||
},
|
||||
{
|
||||
to: '/faq',
|
||||
to: '/integrations',
|
||||
position: 'left',
|
||||
label: 'FAQ',
|
||||
className: 'navbar-item-faq',
|
||||
label: 'Integrations',
|
||||
className: 'navbar-item-integrations',
|
||||
},
|
||||
{
|
||||
to: '/changelog',
|
||||
|
|
|
|||
46
hindsight-docs/src/components/PageHero.module.css
Normal file
46
hindsight-docs/src/components/PageHero.module.css
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
.hero {
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
margin-left: -50vw;
|
||||
/* cancel Docusaurus's margin-vert--lg on the page <main> */
|
||||
margin-top: -2rem;
|
||||
padding: 4rem 1.5rem 3.5rem;
|
||||
text-align: center;
|
||||
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.12) 0%, transparent 70%),
|
||||
var(--ifm-background-color);
|
||||
border-bottom: 1px solid var(--ifm-color-emphasis-200);
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .hero {
|
||||
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.18) 0%, transparent 70%),
|
||||
var(--ifm-background-color);
|
||||
border-bottom-color: rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 3rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #0074d9, #009296);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1.15;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.05rem;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
max-width: 560px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.title {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
}
|
||||
16
hindsight-docs/src/components/PageHero.tsx
Normal file
16
hindsight-docs/src/components/PageHero.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import React, {type ReactNode} from 'react';
|
||||
import styles from './PageHero.module.css';
|
||||
|
||||
interface PageHeroProps {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
}
|
||||
|
||||
export default function PageHero({title, subtitle}: PageHeroProps): ReactNode {
|
||||
return (
|
||||
<div className={styles.hero}>
|
||||
<h1 className={styles.title}>{title}</h1>
|
||||
{subtitle && <p className={styles.subtitle}>{subtitle}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import type {IconType} from 'react-icons';
|
||||
import {IconGrid} from './IconGrid';
|
||||
import {SiPython, SiGo, SiOpenai, SiAnthropic, SiGooglegemini, SiOllama, SiCrewai, SiPydantic, SiVercel} from 'react-icons/si';
|
||||
import {SiPython, SiGo, SiOpenai, SiAnthropic, SiGooglegemini, SiOllama} from 'react-icons/si';
|
||||
import {LuTerminal, LuPlug, LuZap, LuBrainCog, LuSparkles, LuGlobe} from 'react-icons/lu';
|
||||
|
||||
const OpenAICompatibleIcon: IconType = ({size = 28, ...props}) => (
|
||||
|
|
@ -27,22 +27,6 @@ export function ClientsGrid() {
|
|||
);
|
||||
}
|
||||
|
||||
export function IntegrationsGrid() {
|
||||
return (
|
||||
<IconGrid items={[
|
||||
{ label: 'Local 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 SDK', icon: SiVercel, href: '/sdks/integrations/ai-sdk' },
|
||||
{ label: 'Vercel Chat SDK', 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' },
|
||||
]} />
|
||||
);
|
||||
}
|
||||
|
||||
export function LLMProvidersGrid() {
|
||||
return (
|
||||
|
|
|
|||
114
hindsight-docs/src/data/integrations.json
Normal file
114
hindsight-docs/src/data/integrations.json
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
{
|
||||
"integrations": [
|
||||
{
|
||||
"id": "litellm",
|
||||
"name": "LiteLLM",
|
||||
"description": "Add long-term memory to any LLM via LiteLLM proxy callbacks. Zero code changes — configure once and every model gets memory.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/litellm",
|
||||
"icon": "/img/icons/litellm.png"
|
||||
},
|
||||
{
|
||||
"id": "crewai",
|
||||
"name": "CrewAI",
|
||||
"description": "Give CrewAI agents persistent, cross-session memory. Facts learned in one run are available in every future run.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/crewai",
|
||||
"icon": "/img/icons/crewai.png"
|
||||
},
|
||||
{
|
||||
"id": "pydantic-ai",
|
||||
"name": "Pydantic AI",
|
||||
"description": "Integrate Hindsight memory into Pydantic AI agents with a simple dependency injection pattern.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/pydantic-ai",
|
||||
"icon": "/img/icons/pydanticai.png"
|
||||
},
|
||||
{
|
||||
"id": "vercel-ai-sdk",
|
||||
"name": "Vercel AI SDK",
|
||||
"description": "Add persistent memory to Vercel AI SDK applications. Works with any model provider supported by the AI SDK.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/ai-sdk",
|
||||
"icon": "/img/icons/vercel.png"
|
||||
},
|
||||
{
|
||||
"id": "vercel-chat",
|
||||
"name": "Vercel Chat",
|
||||
"description": "Drop-in memory layer for the Vercel AI Chatbot. Remembers users across sessions out of the box.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/chat",
|
||||
"icon": "/img/icons/vercel.png"
|
||||
},
|
||||
{
|
||||
"id": "agno",
|
||||
"name": "Agno",
|
||||
"description": "Plug Hindsight into Agno agents for structured, long-term memory storage and retrieval.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/agno",
|
||||
"icon": "/img/icons/agno.png"
|
||||
},
|
||||
{
|
||||
"id": "hermes",
|
||||
"name": "Hermes",
|
||||
"description": "Use Hindsight as the memory backend for the Hermes multi-agent messaging framework.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/hermes",
|
||||
"icon": "/img/icons/hermes.png"
|
||||
},
|
||||
{
|
||||
"id": "local-mcp",
|
||||
"name": "MCP Server",
|
||||
"description": "Expose Hindsight memory as a Model Context Protocol server. Compatible with Claude, Cursor, and any MCP client.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "mcp",
|
||||
"link": "/sdks/integrations/local-mcp",
|
||||
"icon": "/img/icons/mcp.png"
|
||||
},
|
||||
{
|
||||
"id": "openclaw",
|
||||
"name": "OpenClaw",
|
||||
"description": "Integrate Hindsight with OpenClaw to add memory capabilities to Claude-based agent workflows.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "framework",
|
||||
"link": "/sdks/integrations/openclaw",
|
||||
"icon": "/img/icons/openclaw.png"
|
||||
},
|
||||
{
|
||||
"id": "skills",
|
||||
"name": "Claude Code Skills",
|
||||
"description": "Add Hindsight memory to Claude Code agents via the Skills integration. Persistent context across coding sessions.",
|
||||
"type": "official",
|
||||
"by": "hindsight",
|
||||
"category": "tool",
|
||||
"link": "/sdks/integrations/skills",
|
||||
"icon": "/img/icons/skills.png"
|
||||
},
|
||||
{
|
||||
"id": "hindsight-openclaw-pro",
|
||||
"name": "hindsight-openclaw-pro",
|
||||
"description": "Production-grade Hindsight memory plugin for OpenClaw — per-agent config, multi-bank recall, and IaC bank management via the hoppro CLI.",
|
||||
"type": "community",
|
||||
"by": "mrkhachaturov",
|
||||
"category": "framework",
|
||||
"link": "https://github.com/mrkhachaturov/hindsight-openclaw-pro",
|
||||
"icon": "/img/icons/openclaw.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -4,9 +4,9 @@ description: Practical guidance for agents and developers integrating Hindsight
|
|||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
# Best Practices
|
||||
import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
Practical guidance for agents and developers integrating Hindsight memory into production systems.
|
||||
<PageHero title="Best Practices" subtitle="Practical guidance for agents and developers integrating Hindsight memory into production systems." />
|
||||
|
||||
**Contents**
|
||||
- [Core Concepts](#core-concepts) — Memory banks, taxonomy, memory types
|
||||
|
|
|
|||
|
|
@ -2,22 +2,9 @@
|
|||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
# Changelog
|
||||
import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
This changelog highlights user-facing changes only. Internal maintenance, CI/CD, and infrastructure updates are omitted.
|
||||
|
||||
For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
|
||||
|
||||
## Integration Changelogs
|
||||
|
||||
| Integration | Package | Description |
|
||||
|---|---|---|
|
||||
| [LiteLLM](/changelog/integrations/litellm) | `hindsight-litellm` | Universal LLM memory via LiteLLM (100+ providers) |
|
||||
| [Pydantic AI](/changelog/integrations/pydantic-ai) | `hindsight-pydantic-ai` | Persistent memory tools for Pydantic AI agents |
|
||||
| [CrewAI](/changelog/integrations/crewai) | `hindsight-crewai` | Persistent memory for CrewAI agents |
|
||||
| [AI SDK](/changelog/integrations/ai-sdk) | `@vectorize-io/hindsight-ai-sdk` | Memory integration for Vercel AI SDK |
|
||||
| [Chat SDK](/changelog/integrations/chat) | `@vectorize-io/hindsight-chat` | Memory integration for Vercel Chat SDK |
|
||||
| [OpenClaw](/changelog/integrations/openclaw) | `@vectorize-io/hindsight-openclaw` | Hindsight memory plugin for OpenClaw |
|
||||
<PageHero title="Changelog" subtitle="User-facing changes only. Internal maintenance and infrastructure updates are omitted." />
|
||||
|
||||
## [0.4.19](https://github.com/vectorize-io/hindsight/releases/tag/v0.4.19)
|
||||
|
||||
|
|
@ -606,3 +593,14 @@ For full release details, see [GitHub Releases](https://github.com/vectorize-io/
|
|||
**Bug Fixes**
|
||||
|
||||
- Fixed the standalone Docker image so it builds/runs correctly. ([`1056a20`](https://github.com/vectorize-io/hindsight/commit/1056a20))
|
||||
|
||||
## Integration Changelogs
|
||||
|
||||
| Integration | Package | Description |
|
||||
|---|---|---|
|
||||
| [LiteLLM](/changelog/integrations/litellm) | `hindsight-litellm` | Universal LLM memory via LiteLLM (100+ providers) |
|
||||
| [Pydantic AI](/changelog/integrations/pydantic-ai) | `hindsight-pydantic-ai` | Persistent memory tools for Pydantic AI agents |
|
||||
| [CrewAI](/changelog/integrations/crewai) | `hindsight-crewai` | Persistent memory for CrewAI agents |
|
||||
| [AI SDK](/changelog/integrations/ai-sdk) | `@vectorize-io/hindsight-ai-sdk` | Memory integration for Vercel AI SDK |
|
||||
| [Chat SDK](/changelog/integrations/chat) | `@vectorize-io/hindsight-chat` | Memory integration for Vercel Chat SDK |
|
||||
| [OpenClaw](/changelog/integrations/openclaw) | `@vectorize-io/hindsight-openclaw` | Hindsight memory plugin for OpenClaw |
|
||||
|
|
|
|||
|
|
@ -4,26 +4,12 @@ hide_table_of_contents: true
|
|||
---
|
||||
|
||||
import CookbookGrid from '@site/src/components/CookbookGrid';
|
||||
import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
<PageHero title="Cookbook" subtitle="Practical examples and complete applications built with Hindsight." />
|
||||
|
||||
<div>
|
||||
|
||||
<div style={{textAlign: 'center', marginBottom: '3.5rem'}}>
|
||||
<h1 style={{
|
||||
fontSize: '3rem',
|
||||
fontWeight: 800,
|
||||
background: 'linear-gradient(135deg, #0074d9, #009296)',
|
||||
WebkitBackgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
backgroundClip: 'text',
|
||||
letterSpacing: '-0.03em',
|
||||
lineHeight: 1.15,
|
||||
marginBottom: '0.75rem',
|
||||
}}>Cookbook</h1>
|
||||
<p style={{fontSize: '1.05rem', color: 'var(--ifm-color-emphasis-600)', maxWidth: 520, margin: '0 auto', lineHeight: 1.7}}>
|
||||
Practical examples and complete applications built with Hindsight.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## Recipes
|
||||
|
||||
<CookbookGrid
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ description: Common questions and answers about Hindsight
|
|||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import {ClientsGrid, IntegrationsGrid, LLMProvidersGrid} from '@site/src/components/SupportedGrids';
|
||||
import {ClientsGrid, LLMProvidersGrid} from '@site/src/components/SupportedGrids';
|
||||
import PageHero from '@site/src/components/PageHero';
|
||||
|
||||
# Frequently Asked Questions
|
||||
<PageHero title="FAQ" subtitle="Common questions and answers about Hindsight." />
|
||||
|
||||
**Contents**
|
||||
- [What is Hindsight and how does it differ from RAG?](#what-is-hindsight-and-how-does-it-differ-from-rag)
|
||||
|
|
@ -64,7 +65,7 @@ Unlike vector databases (just search) or RAG systems (document retrieval), Hinds
|
|||
|
||||
### Which integrations are supported?
|
||||
|
||||
<IntegrationsGrid />
|
||||
Browse all supported integrations in the [Integrations Hub](/integrations).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
408
hindsight-docs/src/pages/integrations/index.module.css
Normal file
408
hindsight-docs/src/pages/integrations/index.module.css
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
/* ── Full-width hero ─────────────────────────────────────────────────────── */
|
||||
.heroSection {
|
||||
width: 100%;
|
||||
padding: 5rem 1.5rem 4rem;
|
||||
text-align: center;
|
||||
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.12) 0%, transparent 70%),
|
||||
var(--ifm-background-color);
|
||||
border-bottom: 1px solid var(--ifm-color-emphasis-200);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .heroSection {
|
||||
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0, 116, 217, 0.18) 0%, transparent 70%),
|
||||
var(--ifm-background-color);
|
||||
border-bottom-color: rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
|
||||
.heroTitle {
|
||||
font-size: 3.2rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #0074d9, #009296);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.heroSubtitle {
|
||||
font-size: 1.05rem;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
max-width: 500px;
|
||||
margin: 0 auto 2.25rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* ── Search ──────────────────────────────────────────────────────────────── */
|
||||
.searchWrapper {
|
||||
position: relative;
|
||||
max-width: 640px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.searchInput {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 1.05rem 3.5rem 1.05rem 1.5rem;
|
||||
border-radius: 14px;
|
||||
border: 2px solid var(--ifm-color-emphasis-300);
|
||||
background: var(--ifm-background-surface-color);
|
||||
color: var(--ifm-font-color-base);
|
||||
font-size: 1.1rem;
|
||||
font-family: inherit;
|
||||
outline: none;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.searchInput::placeholder {
|
||||
color: var(--ifm-color-emphasis-400);
|
||||
}
|
||||
|
||||
.searchInput:focus {
|
||||
border-color: #0074d9;
|
||||
box-shadow: 0 0 0 4px rgba(0, 116, 217, 0.15), 0 4px 24px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .searchInput {
|
||||
background: #242428;
|
||||
border-color: rgba(255, 255, 255, 0.15);
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .searchInput:focus {
|
||||
border-color: #4da6ff;
|
||||
box-shadow: 0 0 0 4px rgba(77, 166, 255, 0.18), 0 4px 24px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.searchClear {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: var(--ifm-color-emphasis-200);
|
||||
border: none;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.1s;
|
||||
}
|
||||
|
||||
.searchClear:hover {
|
||||
background: var(--ifm-color-emphasis-300);
|
||||
}
|
||||
|
||||
/* ── Hero stats ──────────────────────────────────────────────────────────── */
|
||||
.heroStats {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
font-size: 0.82rem;
|
||||
color: var(--ifm-color-emphasis-500);
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.stat strong {
|
||||
color: var(--ifm-color-emphasis-800);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .stat strong {
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
}
|
||||
|
||||
.statDivider {
|
||||
color: var(--ifm-color-emphasis-300);
|
||||
}
|
||||
|
||||
/* ── Page container ──────────────────────────────────────────────────────── */
|
||||
.page {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2.5rem 1.5rem 5rem;
|
||||
}
|
||||
|
||||
/* ── Toolbar (filters + count) ───────────────────────────────────────────── */
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1.75rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.filterGroup {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.filterPill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
padding: 0.3rem 0.85rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--ifm-color-emphasis-300);
|
||||
background: transparent;
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.filterPill:hover {
|
||||
border-color: var(--ifm-color-primary);
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
.filterPillActive {
|
||||
background: var(--ifm-color-primary);
|
||||
border-color: var(--ifm-color-primary);
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .filterPill {
|
||||
border-color: rgba(255, 255, 255, 0.15);
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
}
|
||||
|
||||
/* ── Result count ────────────────────────────────────────────────────────── */
|
||||
.resultCount {
|
||||
font-size: 0.8rem;
|
||||
color: var(--ifm-color-emphasis-400);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── Grid ────────────────────────────────────────────────────────────────── */
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1.25rem;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
@media (max-width: 996px) {
|
||||
.grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.grid { grid-template-columns: 1fr; }
|
||||
.heroTitle { font-size: 2.2rem; }
|
||||
}
|
||||
|
||||
/* ── Card ────────────────────────────────────────────────────────────────── */
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--ifm-color-emphasis-200);
|
||||
background: var(--ifm-background-surface-color);
|
||||
text-decoration: none !important;
|
||||
color: inherit;
|
||||
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .card {
|
||||
background: #1c1c1e;
|
||||
border-color: rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 24px rgba(0, 116, 217, 0.12);
|
||||
text-decoration: none !important;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.cardHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 1.1rem 0;
|
||||
}
|
||||
|
||||
.cardIcon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
object-fit: contain;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.typeBadge {
|
||||
font-size: 0.63rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 0.15rem 0.5rem;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.typeBadgeOfficial {
|
||||
background: rgba(0, 116, 217, 0.12);
|
||||
color: #0074d9;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .typeBadgeOfficial {
|
||||
background: rgba(0, 116, 217, 0.2);
|
||||
color: #4da6ff;
|
||||
}
|
||||
|
||||
.typeBadgeCommunity {
|
||||
background: rgba(0, 146, 150, 0.12);
|
||||
color: #009296;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .typeBadgeCommunity {
|
||||
background: rgba(0, 146, 150, 0.2);
|
||||
color: #00bcc0;
|
||||
}
|
||||
|
||||
.cardBody {
|
||||
flex: 1;
|
||||
padding: 0.85rem 1.1rem 0.75rem;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.4rem;
|
||||
color: var(--ifm-heading-color);
|
||||
letter-spacing: -0.01em;
|
||||
border-bottom: none !important;
|
||||
border-image: none !important;
|
||||
}
|
||||
|
||||
.cardDescription {
|
||||
font-size: 0.82rem;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cardFooter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.65rem 1.1rem 0.9rem;
|
||||
margin-top: 0.25rem;
|
||||
border-top: 1px solid var(--ifm-color-emphasis-100);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .cardFooter {
|
||||
border-top-color: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.byLine {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.78rem;
|
||||
font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Monaco, Consolas, monospace;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
}
|
||||
|
||||
.authorIcon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid var(--ifm-color-emphasis-200);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .authorIcon {
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.authorName {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ── Empty state ─────────────────────────────────────────────────────────── */
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 4rem 2rem;
|
||||
color: var(--ifm-color-emphasis-500);
|
||||
}
|
||||
|
||||
.resetButton {
|
||||
margin-top: 1rem;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--ifm-color-primary);
|
||||
background: transparent;
|
||||
color: var(--ifm-color-primary);
|
||||
font-size: 0.85rem;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.resetButton:hover {
|
||||
background: var(--ifm-color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ── Submit banner ───────────────────────────────────────────────────────── */
|
||||
.submitBanner {
|
||||
border-radius: 14px;
|
||||
border: 1px solid var(--ifm-color-emphasis-200);
|
||||
background: linear-gradient(135deg, rgba(0, 116, 217, 0.06), rgba(0, 146, 150, 0.06));
|
||||
padding: 2.5rem 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .submitBanner {
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
background: linear-gradient(135deg, rgba(0, 116, 217, 0.1), rgba(0, 146, 150, 0.1));
|
||||
}
|
||||
|
||||
.submitBannerContent {
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.submitBannerTitle {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.submitBannerText {
|
||||
font-size: 0.9rem;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
margin-bottom: 1.25rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
display: inline-block;
|
||||
padding: 0.55rem 1.4rem;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #0074d9, #009296);
|
||||
color: #fff !important;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none !important;
|
||||
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
|
||||
.submitButton:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
color: #fff !important;
|
||||
}
|
||||
163
hindsight-docs/src/pages/integrations/index.tsx
Normal file
163
hindsight-docs/src/pages/integrations/index.tsx
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
import React, {useMemo, useState} from 'react';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import Layout from '@theme/Layout';
|
||||
import IntegrationsBanner from '@site/src/components/IntegrationsBanner';
|
||||
import integrationsData from '@site/src/data/integrations.json';
|
||||
import styles from './index.module.css';
|
||||
|
||||
const INTEGRATIONS_JSON_URL =
|
||||
'https://github.com/vectorize-io/hindsight/edit/main/hindsight-docs/src/data/integrations.json';
|
||||
|
||||
type IntegrationType = 'official' | 'community';
|
||||
|
||||
interface Integration {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
type: IntegrationType;
|
||||
by: string;
|
||||
category: string;
|
||||
link: string;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
function IntegrationCard({integration}: {integration: Integration}) {
|
||||
const iconSrc = useBaseUrl(integration.icon ?? '');
|
||||
const faviconSrc = useBaseUrl('/img/favicon.png');
|
||||
const isExternal = integration.link.startsWith('http');
|
||||
|
||||
return (
|
||||
<Link to={integration.link} className={styles.card} {...(isExternal ? {target: '_blank', rel: 'noopener noreferrer'} : {})}>
|
||||
<div className={styles.cardHeader}>
|
||||
{integration.icon && <img src={iconSrc} alt="" className={styles.cardIcon} aria-hidden />}
|
||||
<span className={`${styles.typeBadge} ${integration.type === 'official' ? styles.typeBadgeOfficial : styles.typeBadgeCommunity}`}>
|
||||
{integration.type === 'official' ? 'Official' : 'Community'}
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.cardBody}>
|
||||
<h3 className={styles.cardTitle}>{integration.name}</h3>
|
||||
<p className={styles.cardDescription}>{integration.description}</p>
|
||||
</div>
|
||||
<div className={styles.cardFooter}>
|
||||
{integration.type === 'official' ? (
|
||||
<span className={styles.byLine}>
|
||||
<img src={faviconSrc} alt="" className={styles.authorIcon} aria-hidden />
|
||||
<span className={styles.authorName}>Hindsight Team</span>
|
||||
</span>
|
||||
) : (
|
||||
<span className={styles.byLine}>
|
||||
<img src={`https://github.com/${integration.by}.png?size=40`} alt="" className={styles.authorIcon} aria-hidden />
|
||||
<span className={styles.authorName}>@{integration.by}</span>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
export default function IntegrationsHub(): React.ReactElement {
|
||||
const [search, setSearch] = useState('');
|
||||
const [selectedType, setSelectedType] = useState<IntegrationType | 'all'>('all');
|
||||
|
||||
const integrations = integrationsData.integrations as Integration[];
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
const q = search.toLowerCase().trim();
|
||||
return integrations.filter((i) => {
|
||||
if (selectedType !== 'all' && i.type !== selectedType) return false;
|
||||
if (q && !i.name.toLowerCase().includes(q) && !i.description.toLowerCase().includes(q)) return false;
|
||||
return true;
|
||||
});
|
||||
}, [integrations, search, selectedType]);
|
||||
|
||||
const officialCount = integrations.filter((i) => i.type === 'official').length;
|
||||
const communityCount = integrations.filter((i) => i.type === 'community').length;
|
||||
|
||||
return (
|
||||
<Layout title="Integrations Hub" description="Browse official and community integrations for Hindsight agent memory">
|
||||
|
||||
{/* Full-width hero with its own background */}
|
||||
<div className={styles.heroSection}>
|
||||
<h1 className={styles.heroTitle}>Integrations Hub</h1>
|
||||
<p className={styles.heroSubtitle}>
|
||||
Connect Hindsight to your stack. Browse official integrations and community-built connectors.
|
||||
</p>
|
||||
|
||||
<div className={styles.searchWrapper}>
|
||||
<input
|
||||
type="text"
|
||||
className={styles.searchInput}
|
||||
placeholder="Search integrations…"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
aria-label="Search integrations"
|
||||
autoComplete="off"
|
||||
/>
|
||||
{search && (
|
||||
<button className={styles.searchClear} onClick={() => setSearch('')} aria-label="Clear search">
|
||||
×
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.heroStats}>
|
||||
<span className={styles.stat}><strong>{officialCount}</strong> official</span>
|
||||
<span className={styles.statDivider}>·</span>
|
||||
<span className={styles.stat}><strong>{communityCount}</strong> community</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scrolling banner */}
|
||||
<IntegrationsBanner />
|
||||
|
||||
{/* Main content */}
|
||||
<div className={styles.page}>
|
||||
<div className={styles.toolbar}>
|
||||
<div className={styles.filterGroup}>
|
||||
{(['all', 'official', 'community'] as const).map((t) => (
|
||||
<button
|
||||
key={t}
|
||||
className={`${styles.filterPill} ${selectedType === t ? styles.filterPillActive : ''}`}
|
||||
onClick={() => setSelectedType(t)}>
|
||||
{t === 'all' ? 'All' : t.charAt(0).toUpperCase() + t.slice(1)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<span className={styles.resultCount}>{filtered.length} integration{filtered.length !== 1 ? 's' : ''}</span>
|
||||
</div>
|
||||
|
||||
{filtered.length === 0 ? (
|
||||
<div className={styles.empty}>
|
||||
<p>No integrations match your search.</p>
|
||||
<button className={styles.resetButton} onClick={() => { setSearch(''); setSelectedType('all'); }}>
|
||||
Reset filters
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.grid}>
|
||||
{filtered.map((integration) => (
|
||||
<IntegrationCard key={integration.id} integration={integration} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.submitBanner}>
|
||||
<div className={styles.submitBannerContent}>
|
||||
<h2 className={styles.submitBannerTitle}>Built something with Hindsight?</h2>
|
||||
<p className={styles.submitBannerText}>
|
||||
Share your integration with the community. Open a pull request and add your entry to the integrations list.
|
||||
</p>
|
||||
<Link
|
||||
href={INTEGRATIONS_JSON_URL}
|
||||
className={styles.submitButton}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
Submit an integration →
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import Link from '@docusaurus/Link';
|
|||
import Layout from '@theme/Layout';
|
||||
import type {Props} from '@theme/BlogListPage';
|
||||
import type {PropBlogPostContent} from '@docusaurus/plugin-content-blog';
|
||||
import PageHero from '@site/src/components/PageHero';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const CLOUD_TAG = 'hindsight-cloud';
|
||||
|
|
@ -70,10 +71,7 @@ export default function BlogListPage({items, metadata}: Props): React.ReactEleme
|
|||
return (
|
||||
<Layout title={blogTitle} description={blogDescription}>
|
||||
<main className={styles.blogPage}>
|
||||
<header className={styles.header}>
|
||||
<h1 className={styles.headerTitle}>{blogTitle}</h1>
|
||||
{blogDescription && <p className={styles.headerSubtitle}>{blogDescription}</p>}
|
||||
</header>
|
||||
<PageHero title={blogTitle} subtitle={blogDescription} />
|
||||
|
||||
{cloudPosts.length > 0 && (
|
||||
<section className={styles.section}>
|
||||
|
|
|
|||
|
|
@ -1,33 +1,7 @@
|
|||
.blogPage {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 4rem 2rem 6rem;
|
||||
}
|
||||
|
||||
/* ── Header ─────────────────────────────────────── */
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.headerTitle {
|
||||
font-size: 3rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #0074d9, #009296);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.headerSubtitle {
|
||||
font-size: 1.05rem;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
max-width: 520px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.7;
|
||||
padding: 2rem 2rem 6rem;
|
||||
}
|
||||
|
||||
/* ── Section ─────────────────────────────────────── */
|
||||
|
|
@ -93,9 +67,6 @@
|
|||
gap: 2rem;
|
||||
}
|
||||
|
||||
.headerTitle {
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Card ────────────────────────────────────────── */
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
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>
|
||||
<IntegrationsBanner />
|
||||
</>
|
||||
<NavbarLayout>
|
||||
<NavbarContent />
|
||||
</NavbarLayout>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Get up and running with Hindsight in 60 seconds.
|
|||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeSnippet from '@site/src/components/CodeSnippet';
|
||||
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
|
||||
import {ClientsGrid} from '@site/src/components/SupportedGrids';
|
||||
|
||||
{/* Import raw source files */}
|
||||
import quickstartPy from '!!raw-loader!@site/examples/api/quickstart.py';
|
||||
|
|
@ -107,7 +107,7 @@ curl -fsSL https://hindsight.vectorize.io/get-cli | bash
|
|||
|
||||
## Integrations
|
||||
|
||||
<IntegrationsGrid />
|
||||
Browse all supported integrations in the [Integrations Hub](/integrations).
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ sidebar_position: 1
|
|||
slug: /
|
||||
---
|
||||
|
||||
import {ClientsGrid, IntegrationsGrid} from '@site/src/components/SupportedGrids';
|
||||
import {ClientsGrid} from '@site/src/components/SupportedGrids';
|
||||
|
||||
# Overview
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ These settings only affect the `reflect` operation, not `recall`.
|
|||
|
||||
## Integrations
|
||||
|
||||
<IntegrationsGrid />
|
||||
Browse all supported integrations in the [Integrations Hub](/integrations).
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue