'use client'; import Link from 'next/link'; import { useMemo, useState } from 'react'; import { ArrowUpRight } from 'lucide-react'; /* ------------------------------------------------------------------ * * Items come from each example's frontmatter (read in the route from the * examples source). Title + description are the page's own; the `gallery` * block in frontmatter supplies the category lane, toolkit logos, and * featured flag. No per-example config lives in this component. * ------------------------------------------------------------------ */ type Category = 'General agents' | 'Background agents' | 'Coding agents'; /** A resolved example, ready to render. Built in the route from frontmatter. */ export interface GalleryItem { title: string; description: string; href: string; categories: Category[]; logos: string[]; featured?: boolean; order?: number; } /* ------------------------------------------------------------------ * * Category styling — flat editorial tags in the brand accent palette. * Full class strings are written out so Tailwind's JIT keeps them. * ------------------------------------------------------------------ */ interface CatStyle { tag: string; // mono pill on the card dot: string; // filter-pill dot bar: string; // top accent bar on hover } const CATEGORY_STYLES: Record = { 'General agents': { tag: 'text-blue-500 border-blue-500/25 bg-blue-500/[0.06] dark:text-blue-400 dark:border-blue-400/25', dot: 'bg-blue-500 dark:bg-blue-400', bar: 'bg-blue-500 dark:bg-blue-400', }, 'Background agents': { tag: 'text-violet-500 border-violet-500/25 bg-violet-500/[0.06] dark:text-violet-400 dark:border-violet-400/25', dot: 'bg-violet-500 dark:bg-violet-400', bar: 'bg-violet-500 dark:bg-violet-400', }, 'Coding agents': { tag: 'text-emerald-600 border-emerald-500/25 bg-emerald-500/[0.06] dark:text-emerald-400 dark:border-emerald-400/25', dot: 'bg-emerald-600 dark:bg-emerald-400', bar: 'bg-emerald-600 dark:bg-emerald-400', }, }; const CATEGORIES: ('Featured' | Category)[] = [ 'Featured', 'General agents', 'Background agents', 'Coding agents', ]; function logoUrl(name: string) { return `https://logos.composio.dev/api/${name}`; } /* ------------------------------------------------------------------ * * Card * ------------------------------------------------------------------ */ function ExampleCard({ ex, index }: { ex: GalleryItem; index: number }) { // The first category drives the hover accent bar. const primary = CATEGORY_STYLES[ex.categories[0] ?? 'General agents']; return ( {/* top accent bar — grows in on hover */}
{ex.categories.map((cat) => ( {cat} ))}
{ex.logos.length > 0 && (
{ex.logos.map((logo) => ( // eslint-disable-next-line @next/next/no-img-element {logo} ))}
)}

{ex.title}

{ex.description}

Read guide
); } /* ------------------------------------------------------------------ * * Gallery * ------------------------------------------------------------------ */ export function ExamplesGallery({ items }: { items: GalleryItem[] }) { const [active, setActive] = useState<'Featured' | Category>('Featured'); const resolved = useMemo( () => [...items].sort((a, b) => (a.order ?? 99) - (b.order ?? 99)), [items], ); const visible = useMemo(() => { if (active === 'Featured') return resolved.filter((e) => e.featured); return resolved.filter((e) => e.categories.includes(active)); }, [active, resolved]); const countFor = (label: 'Featured' | Category) => label === 'Featured' ? resolved.filter((e) => e.featured).length : resolved.filter((e) => e.categories.includes(label)).length; return (
{/* Hero */}

Examples

Featured examples

End-to-end builds that wire Composio into working agents. Each one is a complete project you can read top to bottom and run.

{/* Filter pills */}
{CATEGORIES.map((label) => { const isActive = active === label; const count = countFor(label); const dot = label === 'Featured' ? undefined : CATEGORY_STYLES[label].dot; return ( ); })}
{/* Grid */} {visible.length > 0 ? (
{visible.map((ex, i) => ( ))}
) : (
More examples in this category are on the way.
)}
); }