diff --git a/.mcp.json b/.mcp.json index 0da2cd6..11633fe 100644 --- a/.mcp.json +++ b/.mcp.json @@ -33,11 +33,14 @@ "DATABASE_URI": "postgresql://banatie_user:banatie_secure_password@localhost:5460/banatie_db" } }, - "mastra": { + "perplexity": { "type": "stdio", "command": "npx", - "args": ["@mastra/mcp-docs-server@latest"], - "env": {} + "args": ["-y", "perplexity-mcp"], + "env": { + "PERPLEXITY_API_KEY": "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", + "PERPLEXITY_TIMEOUT_MS": "600000" + } }, "browsermcp": { "type": "stdio", diff --git a/apps/landing/package.json b/apps/landing/package.json index 3188c77..0f92f17 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -6,7 +6,8 @@ "dev": "next dev -p 3010", "build": "next build", "start": "next start", - "deploy": "cp -r out/* /var/www/banatie.app/" + "deploy": "cp -r out/* /var/www/banatie.app/", + "typecheck": "tsc --noEmit" }, "dependencies": { "react": "19.1.0", diff --git a/apps/landing/src/app/docs/api/text-to-image/page.tsx b/apps/landing/src/app/docs/api/text-to-image/page.tsx new file mode 100644 index 0000000..0d5fb8a --- /dev/null +++ b/apps/landing/src/app/docs/api/text-to-image/page.tsx @@ -0,0 +1,226 @@ +'use client'; + +/** + * API Reference: Text to Image + * + * Refactored to use DocPage component for consistent layout + * Layout handles SubsectionNav and Left Sidebar + * DocPage handles Breadcrumb, Article structure, Next Steps, and TOC + * This page provides only the content (Hero + sections) + */ + +import { TipBox } from '@/components/docs/shared/TipBox'; +import { Table } from '@/components/docs/shared/Table'; +import { CodeBlock } from '@/components/docs/shared/CodeBlock'; +import { DocPage } from '@/components/docs/layout/DocPage'; +import { InteractiveAPIWidget } from '@/components/docs/blocks/InteractiveAPIWidget'; +import { + Hero, + SectionHeader, + InlineCode, + EndpointCard, +} from '@/components/docs/blocks'; + +const tocItems = [ + { id: 'overview', text: 'Overview', level: 2 }, + { id: 'endpoint', text: 'Endpoint', level: 2 }, + { id: 'parameters', text: 'Parameters', level: 2 }, + { id: 'response', text: 'Response', level: 2 }, + { id: 'error-codes', text: 'Error Codes', level: 2 }, + { id: 'interactive', text: 'Try It Live', level: 2 }, + { id: 'next-steps', text: 'Next Steps', level: 2 }, +]; + +const parameters = [ + { name: 'prompt', type: 'string', required: true, description: 'Text description of the image to generate' }, + { name: 'filename', type: 'string', required: false, description: 'Output filename (without extension)' }, + { name: 'aspectRatio', type: 'string', required: false, description: 'Image aspect ratio: "1:1", "16:9", "9:16", "4:3"' }, + { name: 'autoEnhance', type: 'boolean', required: false, description: 'Enable AI prompt enhancement for better results' }, +]; + +export default function TextToImageAPIPage() { + return ( + + + {/* Hero Section */} + + + {/* Overview */} +
+ + Overview + +

+ The Text to Image endpoint allows you to generate images from natural language descriptions. + Powered by Google Gemini 2.5 Flash and Imagen 4.0, it produces photorealistic images + optimized for your specified requirements. +

+ + Tip: Enable autoEnhance + to let AI improve your prompts for better image quality. + +
+ + {/* Endpoint */} +
+ + Endpoint + + +
+ + {/* Parameters */} +
+ + Parameters + +

+ All parameters should be sent in the request body as JSON. +

+ + [ + {param.name}, + {param.type}, + + {param.required ? 'Yes' : 'No'} + , + param.description, + ])} + /> + +
+ + Default Values: If not specified, filename is + auto-generated, aspectRatio defaults + to "1:1", and autoEnhance is false. + +
+ + + {/* Response */} +
+ + Response + +

+ On success, the API returns a JSON object containing the generated image URL and metadata. +

+ + +
+ + {/* Error Codes */} +
+ + Error Codes + +

+ The API uses standard HTTP status codes and returns descriptive error messages. +

+ +
400, + 'Bad Request', + 'Missing or invalid parameters in the request body', + ], + [ + 401, + 'Unauthorized', + 'Missing or invalid API key in X-API-Key header', + ], + [ + 429, + 'Rate Limit', + 'Too many requests. Check rate limit headers for retry timing', + ], + [ + 500, + 'Server Error', + 'Internal server error. Contact support if persists', + ], + ]} + /> + +
+ + Rate Limits: Project API keys are limited to 100 requests per hour. + Upgrade your plan for higher limits. + +
+ + + {/* Interactive Widget */} +
+ + Try It Live + +

+ Test the API directly from this page. Enter your API key and customize the parameters below. +

+ + +
+ + + ); +} diff --git a/apps/landing/src/app/docs/guides/authentication/page.tsx b/apps/landing/src/app/docs/guides/authentication/page.tsx new file mode 100644 index 0000000..e05dac7 --- /dev/null +++ b/apps/landing/src/app/docs/guides/authentication/page.tsx @@ -0,0 +1,313 @@ +'use client'; + +/** + * Authentication Guide + * + * Refactored to use DocPage component for consistent layout + * Layout handles SubsectionNav and Left Sidebar + * DocPage handles Breadcrumb, Article structure, Next Steps, and TOC + * This page provides only the content (Hero + sections) + */ + +import { TipBox } from '@/components/docs/shared/TipBox'; +import { Table } from '@/components/docs/shared/Table'; +import { CodeBlock } from '@/components/docs/shared/CodeBlock'; +import { DocPage } from '@/components/docs/layout/DocPage'; +import { + Hero, + SectionHeader, + InlineCode, +} from '@/components/docs/blocks'; + +const tocItems = [ + { id: 'overview', text: 'Overview', level: 2 }, + { id: 'api-keys', text: 'API Keys', level: 2 }, + { id: 'key-types', text: 'Key Types', level: 3 }, + { id: 'creating-keys', text: 'Creating Keys', level: 3 }, + { id: 'using-keys', text: 'Using API Keys', level: 2 }, + { id: 'rate-limits', text: 'Rate Limits', level: 2 }, + { id: 'security', text: 'Security Best Practices', level: 2 }, + { id: 'next-steps', text: 'Next Steps', level: 2 }, +]; + +export default function AuthenticationGuidePage() { + return ( + + + {/* Hero Section */} + + + {/* Overview */} +
+ + Overview + +

+ Banatie uses API keys to authenticate requests. All API endpoints require authentication + via the X-API-Key header. + API keys are tied to organizations and projects, providing fine-grained access control. +

+ + + Quick Start: New to API authentication? Check out our{' '} + + Getting Started guide + {' '} + for a step-by-step walkthrough. + +
+ + {/* API Keys */} +
+ + API Keys + + +
+ + Key Types + +

+ Banatie supports two types of API keys, each with different permissions and use cases: +

+ +
Master Key, + 'Full admin access, can create/revoke keys', + Never expires, + 'Server-side admin operations, key management', + ], + [ + Project Key, + 'Image generation only', + 90 days, + 'Application integration, API requests', + ], + ]} + /> + +
+ + Master Key Security: Master keys have full + administrative access and never expire. Store them securely in encrypted vaults or + secret managers. Never expose master keys in client-side code, logs, or version control. + Use project keys for application integration whenever possible. + +
+ + +
+ + Creating Keys + +

+ For first-time setup, use the bootstrap endpoint to create your initial master key: +

+ + + +
+

+ Once you have a master key, you can create project keys for your applications: +

+ + +
+
+ + + {/* Using API Keys */} +
+ + Using API Keys + +

+ Include your API key in the X-API-Key header + with every request: +

+ + + +
+ + Environment Variables: Store API keys in environment variables, not + hardcoded in your application. Example:{' '} + BANATIE_API_KEY + +
+
+ + {/* Rate Limits */} +
+ + Rate Limits + +

+ API keys are subject to rate limits to ensure fair usage and system stability. Limits + vary by key type and plan tier: +

+ +
Master Key, + Unlimited, + 'N/A', + 'N/A', + ], + [ + Project Key (Free), + 100 requests/hour, + '1 hour rolling', + Yes, + ], + [ + Project Key (Pro), + 1,000 requests/hour, + '1 hour rolling', + Yes, + ], + ]} + /> + +
+

+ When you exceed rate limits, the API returns a 429 Too Many Requests status. + Check the response headers for retry timing: +

+ + +
+ + + {/* Security Best Practices */} +
+ + Security Best Practices + + + + Critical Security Guidelines: +
    +
  • Never commit API keys to version control systems (Git, SVN, etc.)
  • +
  • Store keys in environment variables or secret management services
  • +
  • Use project keys in applications, reserve master keys for admin operations
  • +
  • Rotate keys regularly, especially after team member changes
  • +
  • Implement server-side API calls for production applications
  • +
  • Monitor API key usage in your dashboard for suspicious activity
  • +
+
+ +
+

Key Rotation Example

+ +
+
+ + + ); +} diff --git a/apps/landing/src/app/docs/layout.tsx b/apps/landing/src/app/docs/layout.tsx new file mode 100644 index 0000000..69e1d52 --- /dev/null +++ b/apps/landing/src/app/docs/layout.tsx @@ -0,0 +1,75 @@ +'use client'; + +import { ReactNode } from 'react'; +import { usePathname } from 'next/navigation'; +import { SubsectionNav } from '@/components/shared/SubsectionNav'; +import { DocsSidebar } from '@/components/docs/layout/DocsSidebar'; +import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout'; + +/** + * Root Documentation Layout + * + * Provides shared layout elements for all documentation pages: + * - SubsectionNav at the top + * - Three-column layout (left sidebar + content + right TOC via DocPage) + * - Background gradients + * + * Uses ThreeColumnLayout for consistent column structure: + * - Left: DocsSidebar (w-64, hidden lg:block) + * - Center: Page content (flex-1) + * - Right: Handled by DocPage component + * + * Pages handle their own: + * - Breadcrumbs (manually specified) + * - Article content + * - TOC sidebar (on the right via DocPage) + * + * Features: + * - Animated gradient background matching landing page + * - Automatic active page detection via pathname + * - Responsive layout (mobile → tablet → desktop) + */ + +interface DocsRootLayoutProps { + children: ReactNode; +} + +const navItems = [ + { label: 'Documentation', href: '/docs' }, + { label: 'Demo', href: '/demo' }, + { label: 'Examples', href: '/docs/examples' }, +]; + +export default function DocsRootLayout({ children }: DocsRootLayoutProps) { + const pathname = usePathname(); + + return ( +
+ {/* Animated gradient background (matching landing page) */} +
+
+
+
+ + {/* Subsection Navigation */} + + + {/* Three-column Documentation Layout */} +
+ + +
+ } + center={children} + /> +
+ + ); +} diff --git a/apps/landing/src/app/docs/page.tsx b/apps/landing/src/app/docs/page.tsx new file mode 100644 index 0000000..a1c3e0b --- /dev/null +++ b/apps/landing/src/app/docs/page.tsx @@ -0,0 +1,196 @@ +'use client'; + +/** + * Getting Started Page - Production Documentation + * + * Refactored to use DocPage component for consistent layout + * Layout handles SubsectionNav and Left Sidebar + * DocPage handles Breadcrumb, Article structure, Next Steps, and TOC + * This page provides only the content (Hero + sections) + */ + +import { TipBox } from '@/components/docs/shared/TipBox'; +import { CodeBlock } from '@/components/docs/shared/CodeBlock'; +import { DocPage } from '@/components/docs/layout/DocPage'; +import { + Hero, + SectionHeader, + ResponseBlock, +} from '@/components/docs/blocks'; + +const tocItems = [ + { id: 'introduction', text: 'Introduction', level: 2 }, + { id: 'quick-start', text: 'Quick Start', level: 2 }, + { id: 'installation', text: 'Installation', level: 3 }, + { id: 'authentication', text: 'Authentication', level: 3 }, + { id: 'first-request', text: 'Your First Request', level: 2 }, + { id: 'next-steps', text: 'Next Steps', level: 2 }, +]; + +export default function GettingStartedPage() { + return ( + + + {/* Hero Section */} + + + {/* Introduction */} +
+ + Introduction + +

+ Banatie is a developer-first API for AI-powered image generation. Built on Google Gemini + 2.5 Flash and Imagen 4.0, it transforms text prompts and reference images into + production-ready visuals. +

+

+ Whether you are building a content creation platform, e-commerce site, or creative tool, + Banatie provides the infrastructure you need to generate high-quality images at scale. +

+ + {/* Compact Tip Box */} + + New to API integration? Start with our{' '} + + code examples + {' '} + to see common use cases in action. + +
+ + {/* Quick Start */} +
+ + Quick Start + + +
+ + Installation + +

+ Banatie is a REST API, so you do not need to install any libraries. However, we provide + SDKs for popular languages to make integration easier. +

+ + +
+ +
+ + Authentication + +

+ All API requests require an API key. You can create an API key from your dashboard or + using the bootstrap endpoint for initial setup. +

+ + {/* Prominent Tip Box for Security Warning */} +
+ + Security Best Practice: Keep your API keys secure. + Never commit them to public repositories or expose them in client-side code. Use environment + variables and server-side implementations for production applications. + +
+ + +
+
+ + {/* First Request */} +
+ + Your First Request + +

+ Let's generate your first image! This example uses curl, but you can use any HTTP client + or our SDKs. +

+ + + +
+

Expected Response:

+ +
+
+ +
+ ); +} diff --git a/apps/landing/src/app/globals.css b/apps/landing/src/app/globals.css index 762d09f..bafa22b 100644 --- a/apps/landing/src/app/globals.css +++ b/apps/landing/src/app/globals.css @@ -62,3 +62,40 @@ body { html { scroll-behavior: smooth; } + +/* Custom Scrollbars for Dark Theme */ +/* Firefox */ +* { + scrollbar-width: thin; + scrollbar-color: rgb(71, 85, 105) rgb(15, 23, 42); /* slate-600 on slate-950 */ +} + +/* Webkit browsers (Chrome, Safari, Edge) */ +*::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +*::-webkit-scrollbar-track { + background: rgb(15, 23, 42); /* slate-950 */ + border-radius: 4px; +} + +*::-webkit-scrollbar-thumb { + background: rgb(71, 85, 105); /* slate-600 */ + border-radius: 4px; + border: 2px solid rgb(15, 23, 42); /* slate-950 */ +} + +*::-webkit-scrollbar-thumb:hover { + background: rgb(100, 116, 139); /* slate-500 */ +} + +/* Code blocks - slightly brighter scrollbar for better visibility */ +pre::-webkit-scrollbar-thumb { + background: rgb(100, 116, 139); /* slate-500 */ +} + +pre::-webkit-scrollbar-thumb:hover { + background: rgb(148, 163, 184); /* slate-400 */ +} diff --git a/apps/landing/src/components/docs/blocks/EndpointCard.tsx b/apps/landing/src/components/docs/blocks/EndpointCard.tsx new file mode 100644 index 0000000..d616f3d --- /dev/null +++ b/apps/landing/src/components/docs/blocks/EndpointCard.tsx @@ -0,0 +1,202 @@ +'use client'; + +/** + * EndpointCard Component + * + * A structured display block for API endpoint information including HTTP method, + * path, and base URL. Creates consistent, scannable API reference documentation. + * + * ## Design Principles + * + * 1. **Information Grouping**: Related endpoint data in one visual container + * - Method badge + endpoint path on same line for scannability + * - Base URL separated below for clarity without clutter + * - Container styling creates clear boundaries + * + * 2. **Visual Hierarchy**: Emphasis guides attention naturally + * - HTTP method badge draws eye first (color + position) + * - Endpoint path is prominent (white text, slightly larger) + * - Base URL is secondary (smaller, muted gray) + * + * 3. **Technical Precision**: Monospace fonts for code accuracy + * - Endpoint path uses code styling + * - Prevents ambiguity in technical content + * - Familiar to developers + * + * ## Layout Strategy + * + * Horizontal Flow: + * ``` + * [METHOD BADGE] /api/endpoint-path + * Base URL: https://api.example.com + * ``` + * + * This layout: + * - Puts most important info (method + path) on top line + * - Creates natural left-to-right reading flow + * - Groups related information visually + * - Works well at various screen sizes + * + * ## Container Styling + * + * Background & Border: + * - bg-slate-900/50: Semi-transparent dark background + * - Separates from page background + * - Maintains dark theme consistency + * - Subtle enough not to dominate + * + * - border-slate-700: Defined edges + * - Creates clear container boundaries + * - Adds structure without heaviness + * - Professional, technical appearance + * + * - rounded-xl: Soft corners (12px radius) + * - Modern, friendly appearance + * - Matches other card elements + * - Balances technical precision with approachability + * + * Padding: + * - p-4 (16px): Comfortable breathing room + * - Prevents cramped appearance + * - Makes content easy to read + * - Balances whitespace and content + * + * ## Typography System + * + * Endpoint Path: + * - text-sm: Slightly smaller than body but clearly readable + * - text-white: Maximum contrast for primary content + * - font-mono implicitly via : Technical accuracy + * + * Base URL: + * - text-xs: Clearly secondary information + * - text-gray-400: Muted to not compete with endpoint + * - Includes "Base URL:" label for context + * + * ## Spacing & Layout + * + * Flex Layout Benefits: + * - items-center: Vertically centers badge with text + * - gap-3 (12px): Comfortable space between badge and path + * - mb-2 (8px): Separates primary info from base URL + * + * ## Usage Examples + * + * ```tsx + * // Standard REST endpoint + * + * + * // Different HTTP methods + * + * + * + * + * // Custom base URL + * + * ``` + * + * ## Content Guidelines + * + * HTTP Method: + * - Always uppercase (GET, POST, PUT, DELETE, PATCH) + * - Choose semantically correct method + * - Follows REST conventions + * + * Endpoint Path: + * - Start with forward slash (/) + * - Use lowercase with hyphens (kebab-case) + * - Include path parameters with colon prefix (:id, :keyId) + * - Be specific and descriptive + * - Example: `/api/projects/:projectId/keys` + * + * Base URL: + * - Include protocol (https://) + * - Use production URL as default + * - No trailing slash + * - Example: `https://api.banatie.com` + * + * ## Accessibility + * + * - Semantic HTML structure + * - Proper contrast ratios for all text + * - MethodBadge includes aria-label + * - Logical reading order (method → path → base) + * - Keyboard accessible (no interactive elements, but focusable context) + * + * ## Visual Language + * + * The EndpointCard establishes: + * - Professional, technical aesthetic + * - Consistent API documentation pattern + * - Clear, unambiguous endpoint identification + * - Easy copy-paste of endpoint information + * - Quick visual scanning in multi-endpoint docs + * + * @component + * @example + * + */ + +import { MethodBadge, HttpMethod } from './MethodBadge'; + +/** + * Props for the EndpointCard component + */ +export interface EndpointCardProps { + /** HTTP method for the endpoint */ + method: HttpMethod; + /** API endpoint path (e.g., "/api/users") */ + endpoint: string; + /** Base URL for the API (default: "https://api.banatie.com") */ + baseUrl?: string; + /** Optional CSS class name for additional styling */ + className?: string; +} + +export const EndpointCard = ({ + method, + endpoint, + baseUrl = 'https://api.banatie.com', + className = '', +}: EndpointCardProps) => { + return ( +
+ {/* Method + Endpoint Row */} +
+ + {endpoint} +
+ + {/* Base URL */} +

+ Base URL: {baseUrl} +

+
+ ); +}; diff --git a/apps/landing/src/components/docs/blocks/Hero.tsx b/apps/landing/src/components/docs/blocks/Hero.tsx new file mode 100644 index 0000000..647eeaf --- /dev/null +++ b/apps/landing/src/components/docs/blocks/Hero.tsx @@ -0,0 +1,185 @@ +'use client'; + +/** + * Hero Component + * + * The primary heading section at the top of documentation pages. + * Establishes visual hierarchy and sets expectations for page content. + * + * ## Design Principles + * + * 1. **Information Hierarchy**: Clear progression from title to description + * - Large, bold title commands attention immediately + * - Subtitle provides context without competing with title + * - Consistent spacing creates rhythm and flow + * + * 2. **Typography Scale**: Responsive sizing for all devices + * - Mobile-first approach with thoughtful breakpoints + * - Maintains readability across screen sizes + * - Proper line-height for comfortable reading + * + * 3. **Visual Weight**: Balanced presence without overwhelming + * - White title for maximum contrast and impact + * - Gray subtitle for supporting, not competing + * - Generous margins create breathing room + * + * ## Size Variants + * + * @param {'default'} default - Standard documentation pages + * - Title: text-4xl (36px) → md:text-5xl (48px) + * - Use cases: API references, guides, tutorials + * - Psychology: Professional, focused, informative + * - Spacing: mb-12 (48px) after hero + * + * @param {'large'} large - Major landing pages, section introductions + * - Title: text-5xl (48px) → md:text-6xl (60px) + * - Use cases: Documentation home, major category pages + * - Psychology: Welcoming, important, primary entry point + * - Spacing: mb-16 (64px) after hero + * + * ## Typographic Hierarchy + * + * Title Characteristics: + * - **Weight**: font-bold (700) - Commands attention + * - **Color**: text-white - Maximum contrast, immediately readable + * - **Spacing**: mb-4 (16px) - Connects title to subtitle + * + * Subtitle Characteristics: + * - **Size**: text-xl (20px) - Large enough to be comfortable, small enough to defer + * - **Weight**: Regular (400) - Contrast with bold title + * - **Color**: text-gray-400 - Supporting role, doesn't compete + * - **Line height**: leading-relaxed (1.625) - Comfortable multi-line reading + * + * ## Responsive Behavior + * + * Mobile (<768px): + * - Smaller text sizes to fit narrow screens + * - Maintains readability with appropriate line lengths + * - Single column layout + * + * Desktop (≥768px): + * - Larger text leverages available space + * - Enhanced visual impact + * - Better use of vertical rhythm + * + * ## Visual Language + * + * The hero serves multiple purposes in documentation: + * 1. **Orientation**: Tells users where they are + * 2. **Context**: Explains what this page covers + * 3. **Hierarchy**: Establishes importance through size + * 4. **Consistency**: Familiarpattern across all docs pages + * + * Color Psychology: + * - **White title**: Authority, clarity, primary information + * - **Gray subtitle**: Support, context, secondary information + * - Creates natural reading flow: bold → light, primary → secondary + * + * ## Accessibility + * + * - Uses semantic HTML (

for title) + * - Proper heading hierarchy (h1 is first heading on page) + * - Sufficient color contrast (white on dark background) + * - Readable font sizes (minimum 20px for subtitle) + * - Appropriate line-height for comfortable reading + * + * ## Usage Examples + * + * ```tsx + * // Standard API reference page + * + * + * // Documentation home page + * + * + * // Guide page + * + * ``` + * + * ## Content Guidelines + * + * Title: + * - Keep short and specific (1-5 words ideal) + * - Use sentence case (capitalize first word only) + * - Avoid punctuation unless necessary + * - Match page's primary purpose + * + * Subtitle: + * - One to two sentences maximum + * - Explain what user will learn or accomplish + * - Use active voice and present tense + * - End with period for complete thoughts + * + * @component + * @example + * + */ + +import { ReactNode } from 'react'; + +/** + * Size variant determining the visual scale of the hero + */ +export type HeroSize = 'default' | 'large'; + +/** + * Props for the Hero component + */ +export interface HeroProps { + /** The main page title (renders as h1) */ + title: string; + /** Supporting description or context */ + subtitle: string | ReactNode; + /** Size variant (default: 'default') */ + size?: HeroSize; + /** Optional CSS class name for additional styling */ + className?: string; +} + +/** + * Title size system mapping size variant to responsive text classes + */ +const titleSizes: Record = { + default: 'text-4xl md:text-5xl', + large: 'text-5xl md:text-6xl', +}; + +/** + * Spacing system for bottom margin + */ +const spacingSizes: Record = { + default: 'mb-12', + large: 'mb-16', +}; + +export const Hero = ({ + title, + subtitle, + size = 'default', + className = '', +}: HeroProps) => { + return ( +
+

+ {title} +

+

+ {subtitle} +

+
+ ); +}; diff --git a/apps/landing/src/components/docs/blocks/InlineCode.tsx b/apps/landing/src/components/docs/blocks/InlineCode.tsx new file mode 100644 index 0000000..758c174 --- /dev/null +++ b/apps/landing/src/components/docs/blocks/InlineCode.tsx @@ -0,0 +1,156 @@ +'use client'; + +/** + * InlineCode Component + * + * A consistent inline code element for technical content within documentation text. + * Provides semantic color variants to emphasize context and meaning. + * + * ## Design Principles + * + * 1. **Readability First**: High contrast with surrounding text + * - Dark background distinguishes code from prose + * - Slightly larger padding creates breathing room + * - Rounded corners soften appearance for inline usage + * + * 2. **Semantic Coloring**: Color conveys meaning beyond monospace + * - Different contexts require different visual emphasis + * - Colors match broader design system for consistency + * - Never rely on color alone (always has monospace + background) + * + * 3. **Typography**: Monospace font signals technical content + * - Built-in font-mono class ensures code appearance + * - Small size (text-sm) fits inline with body text + * - Maintains readability without disrupting flow + * + * ## Color Semantic Values + * + * @param {'primary'} primary - Default technical content, variable names, general code + * - Visual: Purple accent (matches brand primary) + * - Psychology: Neutral technical content, primary focus + * - Use cases: `apiKey`, `userId`, general inline code snippets + * - When to use: Default choice for any code reference + * + * @param {'success'} success - Positive examples, correct values, successful states + * - Visual: Green accent + * - Psychology: Correct, recommended, successful outcome + * - Use cases: `status: 200`, `"success": true`, correct API responses + * - When to use: Showing what TO do, expected good outcomes + * + * @param {'error'} error - Error values, incorrect usage, warnings + * - Visual: Red accent + * - Psychology: Wrong, dangerous, avoid + * - Use cases: `status: 500`, error codes, anti-patterns + * - When to use: Showing what NOT to do, error states + * + * @param {'neutral'} neutral - Informational, documentation, placeholders + * - Visual: Slate/Gray (matches text color scheme) + * - Psychology: Reference, documentation, less emphasis + * - Use cases: HTTP headers like `X-API-Key`, endpoints, technical terms + * - When to use: Supporting information, less critical code references + * + * ## Visual Language + * + * Background Strategy: + * - Dark bg (slate-800) creates clear separation from surrounding text + * - Works on both light and dark documentation themes + * - Sufficient contrast meets WCAG AA standards + * + * Padding Strategy: + * - Horizontal: px-1.5 (6px) - enough space but not disruptive + * - Vertical: py-0.5 (2px) - maintains inline text flow + * - Border radius: rounded (4px) - soft enough for inline, defined enough for blocks + * + * Font Strategy: + * - text-sm: Slightly smaller than body text but still readable + * - font-mono: Clear distinction from prose, signals code + * - font-normal: Not bold, integrates naturally with surrounding text + * + * ## Usage Examples + * + * ```tsx + * // Default technical content + * Set your API_KEY environment variable. + * + * // With semantic colors + * The response includes status: 200. + * Avoid using hardcoded credentials. + * Include the X-API-Key header. + * + * // Parameter documentation + * The autoEnhance parameter defaults to false. + * + * // Error messages + * If you receive 401 Unauthorized, check your API key. + * ``` + * + * ## Composition Guidelines + * + * DO: + * - Use for short code snippets (1-4 words) + * - Use for technical terms, variable names, values + * - Use semantic colors to reinforce meaning + * - Place naturally within sentences + * + * DON'T: + * - Use for multi-line code (use CodeBlock instead) + * - Use for long strings (creates readability issues) + * - Overuse color variants (primary is default for a reason) + * - Use as a design element (it's for code content only) + * + * @component + * @example + * apiKey + */ + +import { ReactNode } from 'react'; + +/** + * Semantic color variants for inline code + */ +export type InlineCodeColor = 'primary' | 'success' | 'error' | 'neutral'; + +/** + * Props for the InlineCode component + */ +export interface InlineCodeProps { + /** The code content to display */ + children: ReactNode; + /** Semantic color variant (default: 'primary') */ + color?: InlineCodeColor; + /** Optional CSS class name for additional styling */ + className?: string; +} + +/** + * Color system mapping semantic meanings to text colors + * All use same dark background for consistency + */ +const colorStyles: Record = { + primary: 'text-purple-400', + success: 'text-green-400', + error: 'text-red-400', + neutral: 'text-gray-400', +}; + +export const InlineCode = ({ + children, + color = 'primary', + className = '', +}: InlineCodeProps) => { + return ( + + {children} + + ); +}; diff --git a/apps/landing/src/components/docs/blocks/InteractiveAPIWidget.tsx b/apps/landing/src/components/docs/blocks/InteractiveAPIWidget.tsx new file mode 100644 index 0000000..8b91a4d --- /dev/null +++ b/apps/landing/src/components/docs/blocks/InteractiveAPIWidget.tsx @@ -0,0 +1,502 @@ +'use client'; + +/** + * Interactive API Widget - Production Version + * + * Minimized layout with clean design system: + * - No inline API key input (uses DocsApiKeyInput component) + * - Clean header with method badge, endpoint, and expand button + * - Full-width code snippet area + * - Compact footer with API key anchor link and Try It button + * - Expanded view opens full-screen modal with code + response side-by-side + */ + +import { useState, useEffect } from 'react'; + +interface InteractiveAPIWidgetProps { + endpoint: string; + method: 'GET' | 'POST' | 'PUT' | 'DELETE'; + description: string; + parameters?: Array<{ + name: string; + type: string; + required: boolean; + description: string; + defaultValue?: string; + }>; +} + +type Language = 'curl' | 'javascript' | 'python' | 'go' | 'js-sdk' | 'mcp'; + +const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'; +const API_KEY_STORAGE = 'banatie_docs_api_key'; + +const getMethodBadgeStyle = (method: string): string => { + switch (method) { + case 'GET': + return 'bg-cyan-600/20 text-cyan-400 border border-cyan-500/40'; + case 'POST': + return 'bg-green-600/20 text-green-400 border border-green-500/40'; + case 'PUT': + return 'bg-amber-600/20 text-amber-400 border border-amber-500/40'; + case 'DELETE': + return 'bg-red-600/20 text-red-400 border border-red-500/40'; + default: + return 'bg-slate-600/20 text-slate-400 border border-slate-500/40'; + } +}; + +export const InteractiveAPIWidget = ({ + endpoint, + method, + description, + parameters = [], +}: InteractiveAPIWidgetProps) => { + const [language, setLanguage] = useState('curl'); + const [apiKey, setApiKey] = useState(''); + const [isExecuting, setIsExecuting] = useState(false); + const [response, setResponse] = useState(null); + const [error, setError] = useState(null); + const [isExpanded, setIsExpanded] = useState(false); + const [paramValues, setParamValues] = useState>({}); + + // Load API key from localStorage and listen for changes + useEffect(() => { + const loadApiKey = () => { + const stored = localStorage.getItem(API_KEY_STORAGE); + if (stored) setApiKey(stored); + }; + + loadApiKey(); + + // Listen for API key changes from DocsApiKeyInput + const handleApiKeyChange = (e: CustomEvent) => { + setApiKey(e.detail); + }; + + window.addEventListener('apiKeyChanged', handleApiKeyChange as EventListener); + + // Initialize parameter defaults + const defaults: Record = { + prompt: 'a futuristic city at sunset', + filename: 'demo', + aspectRatio: '16:9', + }; + + parameters.forEach((param) => { + if (param.defaultValue) { + defaults[param.name] = param.defaultValue; + } + }); + + setParamValues(defaults); + + return () => { + window.removeEventListener('apiKeyChanged', handleApiKeyChange as EventListener); + }; + }, [parameters]); + + // Get language display name + const getLanguageLabel = (lang: Language): string => { + switch (lang) { + case 'curl': + return 'cURL'; + case 'javascript': + return 'JavaScript'; + case 'python': + return 'Python'; + case 'go': + return 'Go'; + case 'js-sdk': + return 'JS SDK'; + case 'mcp': + return 'MCP'; + } + }; + + // Generate code examples + const generateCode = (): string => { + const url = `${API_BASE_URL}${endpoint}`; + + // Coming soon placeholders + if (language === 'js-sdk' || language === 'mcp') { + return `# Coming soon\n# ${getLanguageLabel(language)} integration is under development`; + } + + switch (language) { + case 'curl': + return `curl -X ${method} "${url}" \\ + -H "X-API-Key: ${apiKey || 'YOUR_API_KEY'}" \\ + -H "Content-Type: application/json" \\ + -d '{ + "prompt": "a futuristic city at sunset", + "filename": "city", + "aspectRatio": "16:9" + }'`; + + case 'javascript': + return `const response = await fetch('${url}', { + method: '${method}', + headers: { + 'X-API-Key': '${apiKey || 'YOUR_API_KEY'}', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + prompt: 'a futuristic city at sunset', + filename: 'city', + aspectRatio: '16:9' + }) +}); + +const data = await response.json(); +console.log(data);`; + + case 'python': + return `import requests + +url = '${url}' +headers = { + 'X-API-Key': '${apiKey || 'YOUR_API_KEY'}', + 'Content-Type': 'application/json' +} +data = { + 'prompt': 'a futuristic city at sunset', + 'filename': 'city', + 'aspectRatio': '16:9' +} + +response = requests.${method.toLowerCase()}(url, headers=headers, json=data) +print(response.json())`; + + case 'go': + return `package main + +import ( + "bytes" + "encoding/json" + "net/http" +) + +func main() { + url := "${url}" + data := map[string]interface{}{ + "prompt": "a futuristic city at sunset", + "filename": "city", + "aspectRatio": "16:9", + } + + jsonData, _ := json.Marshal(data) + req, _ := http.NewRequest("${method}", url, bytes.NewBuffer(jsonData)) + req.Header.Set("X-API-Key", "${apiKey || 'YOUR_API_KEY'}") + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, _ := client.Do(req) + defer resp.Body.Close() +}`; + + default: + return ''; + } + }; + + // Execute API request + const executeRequest = async () => { + if (!apiKey) { + setError('Please enter your API key in the top-right corner'); + return; + } + + setIsExecuting(true); + setError(null); + setResponse(null); + + try { + const body = { + prompt: paramValues.prompt || 'a futuristic city at sunset', + filename: paramValues.filename || 'demo', + aspectRatio: paramValues.aspectRatio || '16:9', + }; + + console.log('🔵 API Request:', { + url: `${API_BASE_URL}${endpoint}`, + method, + headers: { 'X-API-Key': apiKey.substring(0, 10) + '...' }, + body, + }); + + const res = await fetch(`${API_BASE_URL}${endpoint}`, { + method, + headers: { + 'X-API-Key': apiKey, + 'Content-Type': 'application/json', + }, + body: method !== 'GET' ? JSON.stringify(body) : undefined, + }); + + console.log('🟢 Response Status:', res.status, res.statusText); + + if (!res.ok) { + let errorMessage = `HTTP ${res.status}: ${res.statusText}`; + try { + const errorData = await res.json(); + errorMessage = errorData.message || errorData.error || errorMessage; + } catch { + // Response is not JSON + } + throw new Error(errorMessage); + } + + const data = await res.json(); + console.log('✅ Response Data:', data); + setResponse(data); + } catch (err) { + console.error('❌ API Error:', err); + const errorMsg = err instanceof Error ? err.message : 'Failed to execute request'; + setError(`Request failed: ${errorMsg}`); + } finally { + setIsExecuting(false); + } + }; + + // Copy code to clipboard + const copyCode = () => { + navigator.clipboard.writeText(generateCode()); + }; + + // Expand API key input in navigation + const expandApiKey = () => { + window.dispatchEvent(new CustomEvent('expandApiKeyInput')); + }; + + const isSuccess = response && response.success === true; + + return ( + <> + {/* Minimized Widget */} +
+ {/* Header */} +
+
+
+ {method} +
+ {endpoint} +
+ +
+ + {/* Code Section - Full Width */} +
+ {/* Language Tabs */} +
+ {(['curl', 'javascript', 'python', 'go', 'js-sdk', 'mcp'] as Language[]).map((lang) => ( + + ))} +
+ + {/* Code Display */} +
+
+ Code Example + +
+
+
+                {generateCode()}
+              
+
+
+
+ + {/* Footer */} +
+ + +
+ + {/* Inline Response (if any) */} + {(response || error) && ( +
+

+ Response +

+ {error ? ( +
+

Error

+

{error}

+
+ ) : ( +
+ {isSuccess && ( +
+ + 200 Success + +
+ )} +
+                  {JSON.stringify(response, null, 2)}
+                
+
+ )} +
+ )} +
+ + {/* Expanded Modal */} + {isExpanded && ( +
+
+ {/* Modal Header */} +
+
+
+
+ {method} +
+ {endpoint} +
+ +

{description}

+
+ +
+ + {/* Two-Panel Layout */} +
+ {/* Left: Code */} +
+
+ {(['curl', 'javascript', 'python', 'go', 'js-sdk', 'mcp'] as Language[]).map((lang) => ( + + ))} +
+ +
+
+ Code Example + +
+
+
+                      {generateCode()}
+                    
+
+
+
+ + {/* Right: Response */} +
+

+ Response +

+ +
+
+ {response && ( + + {response.success ? 'Success' : 'Error'} + + )} +
+
+ {error ? ( +
+

Error

+

{error}

+
+ ) : response ? ( +
+                        {JSON.stringify(response, null, 2)}
+                      
+ ) : ( +
+
+

+ Click "Try It" below to see the response +

+
+
+ )} +
+
+ + {/* Try It Button in Expanded View */} + +
+
+
+
+ )} + + ); +}; diff --git a/apps/landing/src/components/docs/blocks/LinkCard.tsx b/apps/landing/src/components/docs/blocks/LinkCard.tsx new file mode 100644 index 0000000..33f28d5 --- /dev/null +++ b/apps/landing/src/components/docs/blocks/LinkCard.tsx @@ -0,0 +1,281 @@ +'use client'; + +/** + * LinkCard Component + * + * An interactive navigation card for guiding users to related documentation pages. + * Uses color accents and hover effects to create an engaging, explorable experience. + * + * ## Design Principles + * + * 1. **Visual Affordance**: Design signals interactivity + * - Gradient backgrounds hint at clickability + * - Hover states provide immediate feedback + * - Cursor changes to pointer on hover + * - Border transitions guide attention + * + * 2. **Semantic Color System**: Accent colors convey meaning + * - Primary (Purple): Main content, API references + * - Secondary (Cyan): Supporting content, guides + * - Success (Green): Getting started, tutorials + * - Warning (Amber): Important notices, deprecations + * + * 3. **Information Hierarchy**: Title dominates, description supports + * - Large, bold title draws attention + * - Smaller, muted description provides context + * - Title color changes on hover for feedback + * - Clean vertical rhythm (title → description) + * + * ## Accent Color Semantics + * + * @param {'primary'} primary - Main navigational elements, API documentation + * - Visual: Purple gradient and border + * - Psychology: Primary brand, core content, important + * - Use cases: "API Reference", "Core Concepts", main docs + * - Gradient: from-purple-500/10 + * - Hover: border-purple-500/40, text-purple-400 + * + * @param {'secondary'} secondary - Supporting content, guides, tutorials + * - Visual: Cyan gradient and border + * - Psychology: Complementary, helpful, educational + * - Use cases: "Guides", "Tutorials", "Best Practices" + * - Gradient: from-cyan-500/10 + * - Hover: border-cyan-500/40, text-cyan-400 + * + * @param {'success'} success - Getting started, quick wins, positive actions + * - Visual: Green gradient and border + * - Psychology: Achievement, beginning, growth + * - Use cases: "Getting Started", "Quick Start", "First Steps" + * - Gradient: from-green-500/10 + * - Hover: border-green-500/40, text-green-400 + * + * @param {'warning'} warning - Important notices, cautions, deprecations + * - Visual: Amber gradient and border + * - Psychology: Attention, caution, important + * - Use cases: "Migration Guide", "Breaking Changes", "Deprecations" + * - Gradient: from-amber-500/10 + * - Hover: border-amber-500/40, text-amber-400 + * + * ## Interactive States + * + * Default State: + * - Subtle gradient background (from-{color}-500/10) + * - Muted border (border-slate-700/50) + * - White title, gray description + * - Inviting but not demanding attention + * + * Hover State: + * - Border brightens to accent color (/40 opacity) + * - Title transitions to accent color + * - Smooth transition (transition-colors) + * - Clear feedback that element is clickable + * + * ## Layout Structure + * + * Padding System: + * - p-5 (20px): Generous padding for comfortable clicking + * - Creates substantial hit area for accessibility + * - Provides breathing room for content + * + * Border & Radius: + * - rounded-xl (12px): Modern, friendly appearance + * - border: Defined structure + * - Matches other card components in system + * + * ## Typography System + * + * Title (h3): + * - text-lg (18px): Large enough to be primary visual element + * - font-semibold (600): Strong but not overbearing + * - text-white: Maximum contrast and readability + * - mb-2 (8px): Separates from description + * - Transitions to accent color on hover + * + * Description (p): + * - text-sm (14px): Clearly secondary to title + * - text-gray-400: Muted, supporting role + * - Provides context without competing with title + * + * ## Accessibility Features + * + * - Semantic HTML ( tag for links) + * - Proper heading hierarchy (h3 for card titles) + * - Keyboard accessible (focusable link) + * - Sufficient color contrast in all states + * - Large click target (full card clickable) + * - Clear focus states (browser default + hover) + * - Descriptive link text (title + description) + * + * ## Usage Examples + * + * ```tsx + * // Primary content link + * + * + * // Getting started + * + * + * // Supporting guide + * + * + * // Important notice + * + * ``` + * + * ## Content Guidelines + * + * Title: + * - 2-5 words ideal + * - Action-oriented or noun-based + * - Clear and specific + * - Sentence case + * - Examples: "API Reference", "Quick Start", "Authentication Guide" + * + * Description: + * - One sentence (10-20 words) + * - Explain what user will find/learn + * - Start with verb (Explore, Learn, Discover) + * - End with period + * - Be specific about content + * + * Accent Color: + * - Choose based on content type and importance + * - Maintain consistency across similar pages + * - Use primary for most API/core documentation + * - Reserve warning for truly important notices + * + * ## Visual Language + * + * The LinkCard system creates: + * - Intuitive navigation patterns + * - Clear content categorization through color + * - Engaging, explorable documentation + * - Professional yet friendly appearance + * - Consistent user experience across all docs + * + * @component + * @example + * + */ + +/** + * Accent color determining the card's visual theme + */ +export type LinkCardAccent = 'primary' | 'secondary' | 'success' | 'warning'; + +/** + * Props for the LinkCard component + */ +export interface LinkCardProps { + /** Navigation URL */ + href: string; + /** Card title (renders as h3) */ + title: string; + /** Supporting description */ + description: string; + /** Visual accent color */ + accent: LinkCardAccent; + /** Optional icon or emoji to display */ + icon?: string; + /** Optional CSS class name for additional styling */ + className?: string; +} + +/** + * Accent styles mapping color to gradient and hover colors + */ +const accentStyles: Record = { + primary: { + gradient: 'from-purple-500/10', + hoverBorder: 'hover:border-purple-500/40', + hoverText: 'group-hover:text-purple-400', + }, + secondary: { + gradient: 'from-cyan-500/10', + hoverBorder: 'hover:border-cyan-500/40', + hoverText: 'group-hover:text-cyan-400', + }, + success: { + gradient: 'from-green-500/10', + hoverBorder: 'hover:border-green-500/40', + hoverText: 'group-hover:text-green-400', + }, + warning: { + gradient: 'from-amber-500/10', + hoverBorder: 'hover:border-amber-500/40', + hoverText: 'group-hover:text-amber-400', + }, +}; + +export const LinkCard = ({ + href, + title, + description, + accent, + icon, + className = '', +}: LinkCardProps) => { + const styles = accentStyles[accent]; + + return ( + + {icon && ( +
{icon}
+ )} +

+ {title} +

+

+ {description} +

+
+ ); +}; diff --git a/apps/landing/src/components/docs/blocks/LinkCardGrid.tsx b/apps/landing/src/components/docs/blocks/LinkCardGrid.tsx new file mode 100644 index 0000000..b55232c --- /dev/null +++ b/apps/landing/src/components/docs/blocks/LinkCardGrid.tsx @@ -0,0 +1,216 @@ +'use client'; + +/** + * LinkCardGrid Component + * + * A responsive grid layout container for organizing multiple LinkCard components. + * Provides consistent spacing and responsive behavior for navigation card collections. + * + * ## Design Principles + * + * 1. **Responsive Layout**: Adapts gracefully to all screen sizes + * - Mobile: Single column for comfortable tap targets + * - Tablet/Desktop: Multi-column for efficient space usage + * - Fluid transitions between breakpoints + * + * 2. **Grid System**: CSS Grid provides flexible, robust layout + * - Equal-width columns maintain balance + * - Auto-fit for flexible number of cards + * - Consistent gaps create visual rhythm + * + * 3. **Composition Pattern**: Wrapper abstracts layout complexity + * - Parent handles grid logic + * - Children (LinkCards) focus on content + * - Separation of concerns improves maintainability + * + * ## Column Configuration + * + * @param {2} columns=2 - Two-column layout (default) + * - Visual: Balanced, side-by-side comparison + * - Use cases: "Next Steps", paired content, binary choices + * - Responsive: md:grid-cols-2 (2 cols ≥768px, 1 col <768px) + * - Psychology: Compare and choose pattern + * - Example: "API Reference" vs "Authentication Guide" + * + * @param {3} columns=3 - Three-column layout + * - Visual: Information-rich, multiple options + * - Use cases: Resource hubs, category pages, multiple paths + * - Responsive: md:grid-cols-3 (3 cols ≥768px, 1 col <768px) + * - Psychology: Multiple choice, exploration + * - Example: "Getting Started", "API Docs", "Examples" + * + * @param {4} columns=4 - Four-column layout + * - Visual: Dense, comprehensive navigation + * - Use cases: Resource libraries, extensive catalogs + * - Responsive: md:grid-cols-2 lg:grid-cols-4 (2 cols tablet, 4 cols desktop) + * - Psychology: Broad exploration, many options + * - Example: Multiple API endpoints, extensive guides + * + * ## Responsive Breakpoints + * + * Mobile (<768px): + * - All grids collapse to single column + * - Prevents cramped cards on small screens + * - Optimizes for thumb-friendly tap targets + * - Maintains readability and usability + * + * Tablet (≥768px, <1024px): + * - 2-column: Displays as 2 columns + * - 3-column: Displays as 3 columns + * - 4-column: Displays as 2 columns (intermediate step) + * - Balances space usage and readability + * + * Desktop (≥1024px): + * - All grids display at full column count + * - Efficient use of available width + * - Supports quick visual scanning + * + * ## Spacing System + * + * Gap: + * - gap-4 (16px): Comfortable separation between cards + * - Creates visual grouping without crowding + * - Maintains clean grid appearance + * - Consistent with other spacing in design system + * + * Why gap-4? + * - Larger than text line-height (prevents cramping) + * - Small enough to show relationship between cards + * - Works well with card padding (p-5) + * - Scales gracefully at all screen sizes + * + * ## Grid Behavior + * + * CSS Grid Properties: + * - `grid`: Establishes grid container + * - `grid-cols-1`: Mobile baseline (single column) + * - `md:grid-cols-{n}`: Tablet/desktop columns + * - `gap-4`: Gutter between grid items + * + * ## Accessibility Considerations + * + * - Maintains logical reading order (top-to-bottom, left-to-right) + * - Grid doesn't interfere with keyboard navigation + * - Responsive design ensures usability on all devices + * - No JavaScript required (pure CSS grid) + * - Works with screen readers (semantic HTML preserved) + * + * ## Usage Examples + * + * ```tsx + * // Two-column "Next Steps" section + * + * + * + * + * + * // Three-column resource hub + * + * + * + * + * + * + * // Four-column comprehensive navigation + * + * + * + * + * + * + * ``` + * + * ## Composition Guidelines + * + * DO: + * - Use consistent accent colors within a grid (e.g., all primary, or primary + secondary) + * - Keep card count balanced (even numbers work best for 2/4 columns) + * - Provide descriptive, parallel content in cards + * - Order cards by importance or logical flow + * + * DON'T: + * - Mix too many accent colors (creates visual chaos) + * - Use unbalanced card counts in 2-column (odd numbers leave gaps) + * - Nest grids inside grids (causes layout issues) + * - Put non-LinkCard components inside (breaks grid consistency) + * + * ## Visual Language + * + * The LinkCardGrid creates: + * - Organized, scannable navigation patterns + * - Professional documentation architecture + * - Clear visual hierarchy through layout + * - Responsive, mobile-friendly experience + * - Consistent spacing and alignment + * + * ## Performance + * + * - Pure CSS (no JavaScript overhead) + * - Minimal DOM elements (single wrapper div) + * - Hardware-accelerated grid layout + * - No re-renders or layout thrashing + * + * @component + * @example + * + * {children} + * + */ + +import { ReactNode } from 'react'; + +/** + * Column configuration for the grid + */ +export type GridColumns = 2 | 3 | 4; + +/** + * Props for the LinkCardGrid component + */ +export interface LinkCardGridProps { + /** Number of columns at tablet/desktop breakpoints */ + columns?: GridColumns; + /** LinkCard components to display in the grid */ + children: ReactNode; + /** Optional CSS class name for additional styling */ + className?: string; +} + +/** + * Responsive grid class mappings for different column counts + */ +const columnStyles: Record = { + 2: 'md:grid-cols-2', + 3: 'md:grid-cols-3', + 4: 'md:grid-cols-2 lg:grid-cols-4', // 2 cols on tablet, 4 on desktop +}; + +export const LinkCardGrid = ({ + columns = 2, + children, + className = '', +}: LinkCardGridProps) => { + return ( +
+ {children} +
+ ); +}; diff --git a/apps/landing/src/components/docs/blocks/MethodBadge.tsx b/apps/landing/src/components/docs/blocks/MethodBadge.tsx new file mode 100644 index 0000000..b54a492 --- /dev/null +++ b/apps/landing/src/components/docs/blocks/MethodBadge.tsx @@ -0,0 +1,181 @@ +'use client'; + +/** + * MethodBadge Component + * + * A specialized badge for HTTP method display in API documentation. + * Uses industry-standard color conventions to communicate REST operation types. + * + * ## Design Principles + * + * 1. **REST Semantic Mapping**: Colors align with HTTP method semantics + * - Follows industry conventions (GitHub, Stripe, Swagger UI) + * - Immediate visual recognition for developers + * - Consistent with HTTP specification meanings + * + * 2. **Visual Distinction**: Each method has unique, memorable color + * - High contrast for readability against dark backgrounds + * - Distinct enough to differentiate at a glance + * - Professional appearance suitable for technical documentation + * + * 3. **Typography**: Bold, uppercase display reinforces technical nature + * - font-bold for emphasis and readability + * - Uppercase matches HTTP specification format + * - Monospace-friendly sizing + * + * ## HTTP Method Semantics + * + * @param {'GET'} GET - Read/Retrieve operations (Safe, Idempotent) + * - Visual: Cyan/Blue - represents data flow inward (reading) + * - Psychology: Information retrieval, safe operation + * - Use cases: Fetch resources, list endpoints, query data + * - HTTP: Safe method, no side effects, cacheable + * + * @param {'POST'} POST - Create operations (Not safe, Not idempotent) + * - Visual: Green - represents creation, addition, growth + * - Psychology: Positive action, new resource creation + * - Use cases: Create resource, submit form, trigger action + * - HTTP: Creates new resource, may have side effects + * + * @param {'PUT'} PUT - Update/Replace operations (Not safe, Idempotent) + * - Visual: Amber/Orange - represents modification, change + * - Psychology: Caution, transformation, state change + * - Use cases: Update entire resource, replace content + * - HTTP: Idempotent, full resource update + * + * @param {'PATCH'} PATCH - Partial Update operations (Not safe, Not idempotent) + * - Visual: Purple - represents refinement, partial change + * - Psychology: Precision, targeted modification + * - Use cases: Update specific fields, partial resource modification + * - HTTP: Partial update, may not be idempotent + * + * @param {'DELETE'} DELETE - Delete operations (Not safe, Idempotent) + * - Visual: Red - represents removal, destruction, danger + * - Psychology: Warning, irreversible action, stop + * - Use cases: Remove resource, deactivate, destroy data + * - HTTP: Idempotent, removes resource + * + * ## Size Variants + * + * @param {'sm'} sm - Small size for inline usage (px-2 py-0.5, text-xs) + * @param {'md'} md - Medium size for standard usage (px-3 py-1, text-xs) [default] + * + * ## Visual Language + * + * - **Rounded corners**: Modern, friendly appearance + * - **Semi-transparent backgrounds**: Integrates with dark theme + * - **Solid borders**: Adds definition and structure + * - **Bold text**: Ensures readability and emphasis + * - **Consistent sizing**: Aligns with other badges in the design system + * + * Color Opacity Strategy: + * - Background: 20% opacity for subtle presence + * - Border: 40% opacity for clear definition + * - Text: 100% (400 weight) for maximum readability + * + * ## Usage Examples + * + * ```tsx + * // API Endpoint Documentation + * /api/users + * /api/users + * + * // With size variants + * + * + * + * // In endpoint cards + *
+ * + * /api/text-to-image + *
+ * ``` + * + * ## Industry Standards Reference + * + * This color scheme aligns with popular API documentation tools: + * - Swagger UI: Blue (GET), Green (POST), Orange (PUT), Red (DELETE) + * - Postman: Similar color conventions + * - GitHub API Docs: Consistent method color coding + * + * @component + * @example + * + */ + +import { ReactNode } from 'react'; + +/** + * HTTP method types following REST conventions + */ +export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; + +/** + * Size variant for the badge + */ +export type MethodBadgeSize = 'sm' | 'md'; + +/** + * Props for the MethodBadge component + */ +export interface MethodBadgeProps { + /** The HTTP method to display */ + method: HttpMethod; + /** Size variant (default: 'md') */ + size?: MethodBadgeSize; + /** Optional CSS class name for additional styling */ + className?: string; +} + +/** + * Color system mapping HTTP methods to semantic colors + * Follows industry standards for API documentation + */ +const methodStyles: Record = { + GET: 'bg-cyan-600/20 text-cyan-400 border-cyan-500/40', + POST: 'bg-green-600/20 text-green-400 border-green-500/40', + PUT: 'bg-amber-600/20 text-amber-400 border-amber-500/40', + PATCH: 'bg-purple-600/20 text-purple-400 border-purple-500/40', + DELETE: 'bg-red-600/20 text-red-400 border-red-500/40', +}; + +/** + * Size system mapping size variant to padding and font size + */ +const sizeStyles: Record = { + sm: 'px-2 py-0.5 text-xs', + md: 'px-3 py-1 text-xs', +}; + +/** + * Accessibility labels describing the HTTP method's purpose + */ +const methodLabels: Record = { + GET: 'GET request - retrieve data', + POST: 'POST request - create resource', + PUT: 'PUT request - update resource', + PATCH: 'PATCH request - partial update', + DELETE: 'DELETE request - remove resource', +}; + +export const MethodBadge = ({ + method, + size = 'md', + className = '', +}: MethodBadgeProps) => { + return ( + + {method} + + ); +}; diff --git a/apps/landing/src/components/docs/blocks/ResponseBlock.tsx b/apps/landing/src/components/docs/blocks/ResponseBlock.tsx new file mode 100644 index 0000000..f5c108e --- /dev/null +++ b/apps/landing/src/components/docs/blocks/ResponseBlock.tsx @@ -0,0 +1,244 @@ +'use client'; + +/** + * ResponseBlock Component + * + * A semantic display block for API response examples with status indicators. + * Visually differentiates success and error responses through color psychology. + * + * ## Design Principles + * + * 1. **Status Communication**: Color instantly conveys response type + * - Green = Success (2xx responses, positive outcomes) + * - Red = Error (4xx/5xx responses, failures) + * - Consistent with universal traffic light conventions + * + * 2. **Information Layering**: Progressive disclosure of details + * - Status badge in top-right for immediate recognition + * - Optional title provides context + * - Content area for actual response data + * - Layered styling adds depth without clutter + * + * 3. **Visual Feedback**: Subtle effects reinforce status + * - Background tint matches status color + * - Border emphasis adds structure + * - Soft shadow/glow creates depth + * - All at low opacity to avoid overwhelming + * + * ## Status Semantics + * + * @param {'success'} success - Successful API responses (2xx status codes) + * - Visual: Green color palette (green-500) + * - Psychology: Positive, correct, achieved + * - Use cases: 200 OK, 201 Created, 204 No Content + * - Styling: bg-green-500/5, border-green-500/30, shadow-green-500/10 + * - Badge: "✓ 200 Success", "✓ 201 Created" + * + * @param {'error'} error - Error API responses (4xx/5xx status codes) + * - Visual: Red color palette (red-500) + * - Psychology: Warning, problem, attention needed + * - Use cases: 400 Bad Request, 401 Unauthorized, 500 Server Error + * - Styling: bg-red-500/5, border-red-500/30, shadow-red-500/10 + * - Badge: "✗ 400 Error", "✗ 500 Error" + * + * ## Opacity Strategy + * + * Three-tier opacity system: + * - Background: /5 (5% opacity) - Subtle tint, doesn't obscure content + * - Border: /30 (30% opacity) - Clear definition, visible structure + * - Shadow: /10 (10% opacity) - Soft depth, enhances without distraction + * + * This creates: + * - Cohesive visual grouping + * - Clear status communication + * - Maintains content readability + * - Professional, polished appearance + * + * ## Layout Structure + * + * ``` + * ┌─────────────────────────────────────┐ + * │ [STATUS BADGE] ←──┤ Absolute positioned + * │ Optional Title │ + * │ (if provided) │ + * │ │ + * │
                         │
+ * │    Response content                  │
+ * │    ...                               │
+ * │  
│ + * └─────────────────────────────────────┘ + * ``` + * + * Positioning Strategy: + * - Container: relative positioning context + * - Badge: absolute top-3 right-3 (float in top-right) + * - Content: mt-6 when badge present (clear space for badge) + * - Title: mb-3 if provided (separate from content) + * + * ## Typography & Content + * + * Title (optional): + * - text-sm: Small, not competing with main content + * - font-semibold: Subtle emphasis + * - text-gray-300: Readable but secondary + * - Purpose: Labels response type, adds context + * + * Response Content: + * - text-xs: Appropriate for code samples + * - text-gray-300: High contrast on dark background + * - font-mono (implicit in ): Code appearance + * - overflow-x-auto: Handles long lines gracefully + * + * ## Usage Examples + * + * ```tsx + * // Success response with title + * + * + * // Error response without title + * + * + * // Custom status label + * + * ``` + * + * ## Content Guidelines + * + * Response Content: + * - Use actual JSON/text from your API + * - Format with proper indentation (2 or 4 spaces) + * - Include realistic data (not just placeholders) + * - Show relevant fields (omit excessive detail) + * - Keep under 20-30 lines for readability + * + * Status Labels: + * - Include status code (200, 400, etc.) + * - Add descriptive text (Success, Error, Created) + * - Use checkmark (✓) for success + * - Use X (✗) for errors + * - Keep concise (2-3 words max) + * + * ## Accessibility + * + * - Semantic HTML structure (
)
+ * - Color is supplementary (text + symbols)
+ * - High contrast text colors
+ * - StatusBadge includes aria-label
+ * - Proper heading hierarchy if title used
+ * - Scrollable overflow for long content
+ *
+ * ## Visual Language
+ *
+ * The ResponseBlock creates:
+ * - Immediate status recognition through color
+ * - Professional code presentation
+ * - Clear example/documentation relationship
+ * - Consistent pattern across all API docs
+ * - Supports learn-by-example documentation style
+ *
+ * @component
+ * @example
+ * 
+ */
+
+import { StatusBadge, StatusType } from './StatusBadge';
+
+/**
+ * Props for the ResponseBlock component
+ */
+export interface ResponseBlockProps {
+  /** Status type determining color scheme */
+  status: Extract;
+  /** HTTP status code (e.g., 200, 400, 500) */
+  statusCode: number;
+  /** The response content to display (typically JSON) */
+  content: string;
+  /** Optional title above the response */
+  title?: string;
+  /** Optional custom status label (default: auto-generated from statusCode) */
+  statusLabel?: string;
+  /** Optional CSS class name for additional styling */
+  className?: string;
+}
+
+/**
+ * Status styles mapping status type to background, border, and shadow colors
+ */
+const statusStyles = {
+  success: 'bg-green-500/5 border-green-500/30 shadow-lg shadow-green-500/10',
+  error: 'bg-red-500/5 border-red-500/30 shadow-lg shadow-red-500/10',
+};
+
+/**
+ * Generate default status label from code and status
+ */
+const getDefaultStatusLabel = (code: number, status: 'success' | 'error'): string => {
+  const symbol = status === 'success' ? '✓' : '✗';
+  const text = status === 'success' ? 'Success' : 'Error';
+  return `${symbol} ${code} ${text}`;
+};
+
+export const ResponseBlock = ({
+  status,
+  statusCode,
+  content,
+  title,
+  statusLabel,
+  className = '',
+}: ResponseBlockProps) => {
+  const label = statusLabel || getDefaultStatusLabel(statusCode, status);
+
+  return (
+    
+ {/* Status Badge - Floating Top Right */} +
+ + {label} + +
+ + {/* Optional Title */} + {title && ( +

{title}

+ )} + + {/* Response Content */} +
+        {content}
+      
+
+ ); +}; diff --git a/apps/landing/src/components/docs/blocks/SectionHeader.tsx b/apps/landing/src/components/docs/blocks/SectionHeader.tsx new file mode 100644 index 0000000..3398181 --- /dev/null +++ b/apps/landing/src/components/docs/blocks/SectionHeader.tsx @@ -0,0 +1,199 @@ +'use client'; + +/** + * SectionHeader Component + * + * Consistent heading elements for organizing documentation content into hierarchical sections. + * Provides visual rhythm and structure throughout documentation pages. + * + * ## Design Principles + * + * 1. **Visual Hierarchy**: Size and weight indicate content importance + * - Level 2 (h2): Major sections, primary content divisions + * - Level 3 (h3): Subsections, supporting details + * - Consistent styling creates predictable structure + * + * 2. **Semantic HTML**: Proper heading levels for accessibility + * - Uses correct HTML heading tags (h2, h3) + * - Supports screen readers and document outline + * - Enables Table of Contents generation + * - Critical for SEO and document structure + * + * 3. **Spacing System**: Establishes vertical rhythm + * - Top margin separates from previous content + * - Bottom margin creates breathing room before content + * - Consistent spacing improves scannability + * + * ## Heading Level Semantics + * + * @param {2} level2 - Major section headings (h2) + * - Visual: text-3xl (30px), font-bold, text-white + * - Spacing: mb-4 (16px) below, mb-6 (24px) for sections with mb-12 + * - Psychology: Primary divisions, main topics + * - Use cases: "Overview", "Parameters", "Response", "Error Codes" + * - Hierarchy: Second level (after page h1/Hero) + * - SEO: Key topic signals for search engines + * + * @param {3} level3 - Subsection headings (h3) + * - Visual: text-xl (20px), font-semibold, text-white + * - Spacing: mb-3 (12px) below, mb-4 (16px) for subsections with mb-8 + * - Psychology: Supporting topics, detailed breakdowns + * - Use cases: "Key Types", "Creating Keys", "Rate Limits" + * - Hierarchy: Third level (under h2 sections) + * - SEO: Supporting detail signals + * + * ## Typography Scale Reasoning + * + * Level 2 (text-3xl / 30px): + * - Large enough to clearly mark major sections + * - Smaller than Hero (36-48px) to maintain hierarchy + * - Bold weight adds emphasis and structure + * - White color ensures readability and prominence + * + * Level 3 (text-xl / 20px): + * - Noticeably smaller than h2, maintaining hierarchy + * - Semibold (600) instead of bold provides subtle distinction + * - Large enough to serve as clear subsection marker + * - Balances prominence with subordinate role + * + * ## Spacing Philosophy + * + * Bottom Margin Strategy: + * - h2: mb-4 or mb-6 depending on section context + * - mb-4 for tighter sections with nearby content + * - mb-6 for major sections introducing substantial content + * - h3: mb-3 or mb-4 depending on subsection context + * - Smaller margins reflect subordinate hierarchy + * - Still provides clear separation from content + * + * ## Anchor Link Support + * + * The `id` prop enables: + * - Direct linking to specific sections (#section-name) + * - Table of Contents navigation + * - Deep linking from external sources + * - Browser history for scrolled positions + * + * ID Naming Convention: + * - Use kebab-case (lowercase with hyphens) + * - Descriptive and unique per page + * - Example: "api-keys", "rate-limits", "error-handling" + * + * ## Accessibility Features + * + * - Semantic HTML heading levels (h2, h3) + * - Proper document outline structure + * - Sufficient color contrast (white on dark) + * - Clear visual distinction between levels + * - Screen reader friendly navigation + * - Keyboard accessible anchor links + * + * ## Usage Examples + * + * ```tsx + * // Major section heading (h2) + * + * Overview + * + * + * // Subsection heading (h3) + * + * Key Types + * + * + * // Custom spacing with className + * + * Parameters + * + * ``` + * + * ## Content Guidelines + * + * Level 2 Headings: + * - 1-3 words ideal (concise and scannable) + * - Sentence case (capitalize first word) + * - Action-oriented or descriptive nouns + * - Examples: "Quick Start", "Authentication", "Rate Limits" + * + * Level 3 Headings: + * - 1-4 words, slightly more descriptive + * - Sentence case + * - Specific subtopics or steps + * - Examples: "Creating Keys", "Using API Keys", "Security Best Practices" + * + * ## Visual Language + * + * The header system creates a visual rhythm that: + * - Guides the eye through content naturally + * - Breaks long pages into digestible chunks + * - Signals importance through size and weight + * - Maintains consistency across all documentation + * - Supports quick scanning and navigation + * + * @component + * @example + * + * Getting Started + * + */ + +import { ReactNode } from 'react'; + +/** + * Heading level determining HTML tag and visual styling + */ +export type SectionHeaderLevel = 2 | 3; + +/** + * Props for the SectionHeader component + */ +export interface SectionHeaderProps { + /** Heading level (h2 or h3) for semantic structure */ + level: SectionHeaderLevel; + /** The heading text content */ + children: ReactNode; + /** Optional ID for anchor linking and table of contents */ + id?: string; + /** Optional CSS class name for additional styling (e.g., custom margins) */ + className?: string; +} + +/** + * Typography styles mapping heading level to text size and weight + */ +const levelStyles: Record = { + 2: 'text-3xl font-bold', + 3: 'text-xl font-semibold', +}; + +/** + * Default spacing system for bottom margins + */ +const defaultSpacing: Record = { + 2: 'mb-4', + 3: 'mb-3', +}; + +export const SectionHeader = ({ + level, + children, + id, + className, +}: SectionHeaderProps) => { + const Tag = `h${level}` as 'h2' | 'h3'; + const spacing = className?.includes('mb-') ? '' : defaultSpacing[level]; + + return ( + + {children} + + ); +}; diff --git a/apps/landing/src/components/docs/blocks/StatusBadge.tsx b/apps/landing/src/components/docs/blocks/StatusBadge.tsx new file mode 100644 index 0000000..169ac41 --- /dev/null +++ b/apps/landing/src/components/docs/blocks/StatusBadge.tsx @@ -0,0 +1,176 @@ +'use client'; + +/** + * StatusBadge Component + * + * A semantic status indicator that uses color psychology and consistent styling + * to communicate state, result, or severity across documentation. + * + * ## Design Principles + * + * 1. **Semantic Color System**: Colors convey meaning, not just decoration + * - Uses consistent color mapping across all documentation + * - Follows industry standards (green = success, red = error, etc.) + * + * 2. **Visual Hierarchy**: Small, unobtrusive elements that enhance readability + * - Pill-shaped design for friendly, modern appearance + * - Subtle backgrounds with semi-transparent colors + * - Border emphasis for definition without heaviness + * + * 3. **Accessibility**: Meets WCAG 2.1 AA standards + * - Sufficient color contrast ratios + * - Semantic HTML with aria-label + * - Text labels (never color-only communication) + * + * ## Semantic Status Values + * + * @param {'success'} success - Positive outcomes, completed actions, 2xx HTTP responses + * - Visual: Green color palette + * - Psychology: Achievement, correctness, go-ahead signal + * - Use cases: "200 Success", "Completed", "Active", "✓ Passed" + * + * @param {'info'} info - Neutral information, documentation, helpful tips + * - Visual: Blue/Cyan color palette + * - Psychology: Calm, trustworthy, educational + * - Use cases: "Beta", "New", "Info", "Note" + * + * @param {'warning'} warning - Caution, deprecation, rate limits, 4xx client errors + * - Visual: Amber/Orange color palette + * - Psychology: Attention needed, proceed with caution + * - Use cases: "429 Rate Limit", "Deprecated", "Warning", "Limited" + * + * @param {'error'} error - Failures, critical issues, 5xx server errors, security alerts + * - Visual: Red color palette + * - Psychology: Stop, danger, requires immediate attention + * - Use cases: "500 Error", "Failed", "Critical", "Blocked" + * + * @param {'neutral'} neutral - Default state, placeholder, unspecified + * - Visual: Slate/Gray color palette + * - Psychology: Neutral, balanced, inactive + * - Use cases: "Pending", "Unknown", "Draft", "Inactive" + * + * ## Size Variants + * + * @param {'sm'} sm - Small size for inline usage, tight spaces + * - Font: text-xs + * - Padding: px-2 py-0.5 + * - Use: Inline with text, table cells, compact layouts + * + * @param {'md'} md - Medium size (default) for standard usage + * - Font: text-xs + * - Padding: px-3 py-1 + * - Use: General purpose, code examples, section markers + * + * ## Visual Language + * + * The badge uses a rounded-full design (pill shape) which: + * - Creates visual consistency with other UI elements (buttons, tags) + * - Feels modern and friendly (vs. harsh rectangular badges) + * - Groups related information visually + * - Works well at small sizes without appearing cramped + * + * Color opacity levels (X/20 bg, X/40 border): + * - Background: 20% opacity for subtle presence + * - Border: 40% opacity for definition + * - Text: 100% for maximum readability + * + * ## Usage Examples + * + * ```tsx + * // HTTP Status Codes + * 200 OK + * 500 Error + * + * // API States + * Beta + * Deprecated + * + * // System Status + * ✓ Active + * Pending + * ``` + * + * @component + * @example + * 200 Success + */ + +import { ReactNode } from 'react'; + +/** + * Semantic status type representing the meaning/severity of the badge + */ +export type StatusType = 'success' | 'info' | 'warning' | 'error' | 'neutral'; + +/** + * Size variant for the badge + */ +export type StatusSize = 'sm' | 'md'; + +/** + * Props for the StatusBadge component + */ +export interface StatusBadgeProps { + /** The semantic status that determines color and meaning */ + status: StatusType; + /** The content to display inside the badge */ + children: ReactNode; + /** Size variant (default: 'md') */ + size?: StatusSize; + /** Optional CSS class name for additional styling */ + className?: string; +} + +/** + * Color system mapping semantic status to Tailwind color utilities + * Follows the established design system color palette + */ +const statusStyles: Record = { + success: 'bg-green-500/20 text-green-400 border border-green-500/40', + info: 'bg-cyan-500/20 text-cyan-400 border border-cyan-500/40', + warning: 'bg-amber-500/20 text-amber-400 border border-amber-500/40', + error: 'bg-red-500/20 text-red-400 border border-red-500/40', + neutral: 'bg-slate-500/20 text-slate-400 border border-slate-500/40', +}; + +/** + * Size system mapping size variant to padding and font size + */ +const sizeStyles: Record = { + sm: 'px-2 py-0.5 text-xs', + md: 'px-3 py-1 text-xs', +}; + +/** + * Human-readable labels for screen readers + */ +const statusLabels: Record = { + success: 'Success status', + info: 'Information status', + warning: 'Warning status', + error: 'Error status', + neutral: 'Neutral status', +}; + +export const StatusBadge = ({ + status, + children, + size = 'md', + className = '', +}: StatusBadgeProps) => { + return ( + + {children} + + ); +}; diff --git a/apps/landing/src/components/docs/blocks/index.ts b/apps/landing/src/components/docs/blocks/index.ts new file mode 100644 index 0000000..1f5de28 --- /dev/null +++ b/apps/landing/src/components/docs/blocks/index.ts @@ -0,0 +1,176 @@ +/** + * Documentation Block Components + * + * A comprehensive library of reusable, semantic components for building + * consistent, professional API documentation. + * + * ## Design System Overview + * + * This collection establishes a visual language for documentation through: + * - **Semantic Color System**: Enum-based color values with clear meanings + * - **Consistent Typography**: Hierarchical text sizing and weights + * - **Responsive Layouts**: Mobile-first, adaptive components + * - **Accessibility First**: WCAG 2.1 AA compliance throughout + * - **Comprehensive Documentation**: Every component fully documented + * + * ## Component Categories + * + * ### Status & Indicators + * - **StatusBadge**: Semantic status indicators (success, info, warning, error, neutral) + * - **MethodBadge**: HTTP method badges (GET, POST, PUT, PATCH, DELETE) + * + * ### Typography & Content + * - **Hero**: Page-level headings with title and subtitle + * - **SectionHeader**: Hierarchical section headings (h2, h3) + * - **InlineCode**: Semantic inline code elements + * + * ### API Documentation + * - **EndpointCard**: Structured API endpoint display + * - **ResponseBlock**: API response examples with status visualization + * + * ### Navigation + * - **LinkCard**: Interactive navigation cards with accent colors + * - **LinkCardGrid**: Responsive grid layout for link cards + * + * ## Usage Philosophy + * + * These components follow key principles: + * + * 1. **Composition over Configuration** + * - Small, focused components combine to create pages + * - Each component does one thing well + * - Easy to understand and maintain + * + * 2. **Semantic Props** + * - Enum values over raw values (accent='primary' not color='#8b5cf6') + * - Meaning-based names (status='success' not color='green') + * - Self-documenting API + * + * 3. **Consistent Patterns** + * - Similar props across components (className, children) + * - Predictable behavior and styling + * - Easy to learn and use + * + * 4. **Accessibility Built-in** + * - Semantic HTML throughout + * - ARIA labels where appropriate + * - Keyboard navigation support + * - Sufficient color contrast + * + * ## Example: Building a Documentation Page + * + * ```tsx + * import { + * Hero, + * SectionHeader, + * InlineCode, + * EndpointCard, + * ResponseBlock, + * LinkCard, + * LinkCardGrid, + * } from '@/components/docs/blocks'; + * + * export default function APIPage() { + * return ( + * <> + * + * + * + * Endpoint + * + * + * + * + * + * Response + * + * + * + * + * + * Next Steps + * + * + * + * + * + * + * + * ); + * } + * ``` + * + * ## Color System Reference + * + * ### Semantic Colors + * - **primary**: Purple - Brand primary, main content + * - **secondary**: Cyan - Complementary, supporting content + * - **success**: Green - Positive outcomes, achievements + * - **info**: Blue/Cyan - Informational, neutral + * - **warning**: Amber - Caution, important notices + * - **error**: Red - Errors, problems, danger + * - **neutral**: Slate/Gray - Default, inactive + * + * ### HTTP Method Colors + * - **GET**: Cyan - Read operations + * - **POST**: Green - Create operations + * - **PUT**: Amber - Update operations + * - **PATCH**: Purple - Partial update + * - **DELETE**: Red - Delete operations + * + * ## Spacing System + * + * Consistent spacing creates visual rhythm: + * - **sm**: Tight spacing for compact layouts + * - **md**: Standard spacing (default for most components) + * - **lg**: Generous spacing for major sections + * + * ## Typography Scale + * + * Hierarchical text sizing: + * - **Hero**: text-4xl → text-6xl (large, page-level) + * - **H2**: text-3xl (section headings) + * - **H3**: text-xl (subsection headings) + * - **Body**: text-base (paragraph text) + * - **Small**: text-sm (supporting text) + * - **Code**: text-xs (code samples) + * + * @module blocks + */ + +// Status & Indicators +export { StatusBadge, type StatusBadgeProps, type StatusType, type StatusSize } from './StatusBadge'; +export { MethodBadge, type MethodBadgeProps, type HttpMethod, type MethodBadgeSize } from './MethodBadge'; + +// Typography & Content +export { Hero, type HeroProps, type HeroSize } from './Hero'; +export { SectionHeader, type SectionHeaderProps, type SectionHeaderLevel } from './SectionHeader'; +export { InlineCode, type InlineCodeProps, type InlineCodeColor } from './InlineCode'; + +// API Documentation +export { EndpointCard, type EndpointCardProps } from './EndpointCard'; +export { ResponseBlock, type ResponseBlockProps } from './ResponseBlock'; + +// Navigation +export { LinkCard, type LinkCardProps, type LinkCardAccent } from './LinkCard'; +export { LinkCardGrid, type LinkCardGridProps, type GridColumns } from './LinkCardGrid'; diff --git a/apps/landing/src/components/docs/layout/DocPage.tsx b/apps/landing/src/components/docs/layout/DocPage.tsx new file mode 100644 index 0000000..3b5ff94 --- /dev/null +++ b/apps/landing/src/components/docs/layout/DocPage.tsx @@ -0,0 +1,142 @@ +'use client'; + +/** + * Documentation Page Layout Component + * + * Provides consistent structure for all documentation pages: + * - Breadcrumb navigation at top + * - Article content area (passed as children) + * - Next Steps section at bottom + * - Table of Contents sidebar on the right + * + * Uses ThreeColumnLayout for consistent column structure: + * - Center: Article content (max-w-3xl) + * - Right: Table of Contents (w-56, hidden xl:block) + * + * This component extracts common layout patterns from all doc pages, + * reducing duplication and ensuring consistency. + * + * Usage: + * ```tsx + * + * + *
...
+ *
+ * ``` + */ + +import { ReactNode } from 'react'; +import { Breadcrumb } from '@/components/docs/shared/Breadcrumb'; +import { DocsTOC } from '@/components/docs/layout/DocsTOC'; +import { SectionHeader, LinkCard, LinkCardGrid } from '@/components/docs/blocks'; +import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout'; + +/** + * Next step link card configuration + */ +export interface NextStepLink { + href: string; + title: string; + description: string; + accent: 'primary' | 'secondary' | 'success' | 'warning'; +} + +/** + * Table of Contents item + */ +export interface TocItem { + id: string; + text: string; + level: number; +} + +/** + * Breadcrumb navigation item + */ +export interface BreadcrumbItem { + label: string; + href?: string; +} + +/** + * DocPage component props + */ +export interface DocPageProps { + /** Breadcrumb navigation items (top of page) */ + breadcrumbItems: BreadcrumbItem[]; + + /** Table of contents items (right sidebar) */ + tocItems: TocItem[]; + + /** Next steps section configuration */ + nextSteps: { + /** Optional description text before link cards */ + description?: string; + /** Link cards to display (typically 2) */ + links: NextStepLink[]; + }; + + /** Page content (Hero, sections, etc.) */ + children: ReactNode; +} + +/** + * Documentation Page Layout Component + * + * Wraps documentation content with consistent structure including + * breadcrumbs, TOC sidebar, and next steps section. + */ +export const DocPage = ({ + breadcrumbItems, + tocItems, + nextSteps, + children, +}: DocPageProps) => { + return ( + + {/* Breadcrumb Navigation */} + + + {/* Page Content (Hero + Sections) */} + {children} + + {/* Next Steps Section */} +
+ + Next Steps + + + {nextSteps.description && ( +

+ {nextSteps.description} +

+ )} + + + {nextSteps.links.map((link, index) => ( + + ))} + +
+ + } + right={ +
+ +
+ } + /> + ); +}; diff --git a/apps/landing/src/components/docs/layout/DocsLayout.tsx b/apps/landing/src/components/docs/layout/DocsLayout.tsx new file mode 100644 index 0000000..10bde15 --- /dev/null +++ b/apps/landing/src/components/docs/layout/DocsLayout.tsx @@ -0,0 +1,64 @@ +'use client'; + +/** + * Documentation Layout - Production Version + * + * Based on Variant A: Clean & Minimal with enhancements + * This is the production-ready version combining the best aspects + * + * Layout Structure: + * - Left Sidebar: Thin (256px) with minimal design + * - Content Area: Wide margins (max-w-3xl) for comfortable reading + * - Right TOC: Subtle and unobtrusive (224px) + * + * Responsive Behavior: + * - Mobile (<768px): Single column, sidebars become overlays + * - Tablet (768px-1024px): Content + TOC only + * - Desktop (>1024px): Full three-column layout + * + * Design Characteristics: + * - Generous whitespace + * - Subtle borders and shadows + * - Focus on content clarity + * - Minimal visual noise + * - Accessibility compliant (WCAG 2.1 AA) + */ + +import { ReactNode } from 'react'; + +interface DocsLayoutProps { + sidebar: ReactNode; + children: ReactNode; + toc: ReactNode; +} + +export const DocsLayout = ({ sidebar, children, toc }: DocsLayoutProps) => { + return ( +
+ {/* Animated gradient background (matching landing page) */} +
+
+
+
+ +
+ {/* Left Sidebar - Thin, minimal design */} + + + {/* Main Content Area - Wide margins for comfortable reading */} +
+
+ {children} +
+
+ + {/* Right TOC - Subtle and unobtrusive */} + +
+
+ ); +}; diff --git a/apps/landing/src/components/docs/layout/DocsSidebar.tsx b/apps/landing/src/components/docs/layout/DocsSidebar.tsx new file mode 100644 index 0000000..b5e6d6a --- /dev/null +++ b/apps/landing/src/components/docs/layout/DocsSidebar.tsx @@ -0,0 +1,181 @@ +'use client'; + +/** + * Documentation Sidebar - Production Version + * + * Based on Variant A with FIXED active states + * + * Key Improvements: + * - Consistent active state styling for both parent and child items + * - Clean left border indicator (no background boxes) + * - Parent active: purple left border + white text + * - Child active: purple left border + white text (NO background) + * + * Features: + * - Thin sidebar with subtle hover states + * - Collapsible section groups + * - Minimal icons (chevron for expandable items) + * - Clean, uncluttered appearance + * + * Navigation Structure: + * - Getting Started + * - API Reference (collapsible) + * - Guides (collapsible) + * - Examples + */ + +import { useState } from 'react'; + +interface NavItem { + label: string; + href: string; + icon?: string; + children?: NavItem[]; +} + +interface DocsSidebarProps { + currentPath: string; +} + +const navigationItems: NavItem[] = [ + { + label: 'Getting Started', + href: '/docs', + icon: '🚀', + }, + { + label: 'API Reference', + href: '/docs/api', + icon: '📚', + children: [ + { label: 'Text to Image', href: '/docs/api/text-to-image' }, + { label: 'Upload', href: '/docs/api/upload' }, + { label: 'Images', href: '/docs/api/images' }, + ], + }, + { + label: 'Guides', + href: '/docs/guides', + icon: '📖', + children: [ + { label: 'Authentication', href: '/docs/guides/authentication' }, + { label: 'Error Handling', href: '/docs/guides/error-handling' }, + { label: 'Rate Limits', href: '/docs/guides/rate-limits' }, + ], + }, + { + label: 'Examples', + href: '/docs/examples', + icon: '💡', + }, +]; + +export const DocsSidebar = ({ currentPath }: DocsSidebarProps) => { + const [expandedSections, setExpandedSections] = useState(['API Reference', 'Guides']); + + const toggleSection = (label: string) => { + setExpandedSections((prev) => + prev.includes(label) ? prev.filter((item) => item !== label) : [...prev, label] + ); + }; + + const isActive = (href: string) => currentPath === href; + const isExpanded = (label: string) => expandedSections.includes(label); + + return ( + + ); +}; diff --git a/apps/landing/src/components/docs/layout/DocsTOC.tsx b/apps/landing/src/components/docs/layout/DocsTOC.tsx new file mode 100644 index 0000000..5b0ca3d --- /dev/null +++ b/apps/landing/src/components/docs/layout/DocsTOC.tsx @@ -0,0 +1,102 @@ +'use client'; + +/** + * Table of Contents - Production Version + * + * Based on Variant A: Clean & Minimal (no changes needed) + * + * Features: + * - Small indicator dots for section levels + * - Smooth scroll to section + * - Active section highlighting (purple text) + * - Sticky positioning + * - Minimal visual weight + * + * Behavior: + * - Extracts H2 and H3 headings from content + * - Tracks scroll position to highlight active section + * - Click to smooth scroll to section + */ + +import { useEffect, useState } from 'react'; + +interface TocItem { + id: string; + text: string; + level: number; +} + +interface DocsTOCProps { + items: TocItem[]; +} + +export const DocsTOC = ({ items }: DocsTOCProps) => { + const [activeId, setActiveId] = useState(''); + + useEffect(() => { + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + setActiveId(entry.target.id); + } + }); + }, + { rootMargin: '-20% 0px -35% 0px' } + ); + + items.forEach((item) => { + const element = document.getElementById(item.id); + if (element) observer.observe(element); + }); + + return () => observer.disconnect(); + }, [items]); + + const scrollToSection = (id: string) => { + const element = document.getElementById(id); + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + }; + + if (items.length === 0) { + return null; + } + + return ( + + ); +}; diff --git a/apps/landing/src/components/docs/shared/Breadcrumb.tsx b/apps/landing/src/components/docs/shared/Breadcrumb.tsx new file mode 100644 index 0000000..3656001 --- /dev/null +++ b/apps/landing/src/components/docs/shared/Breadcrumb.tsx @@ -0,0 +1,73 @@ +'use client'; + +/** + * Breadcrumb Navigation Component + * + * Displays hierarchical navigation path for documentation pages. + * Follows WCAG 2.1 AA accessibility guidelines with proper ARIA labels. + * + * Design: + * - Consistent with Banatie dark theme + * - Gray text with white hover for inactive items + * - White text for current page + * - Chevron separators between items + */ + +interface BreadcrumbItem { + label: string; + href?: string; +} + +interface BreadcrumbProps { + items: BreadcrumbItem[]; +} + +export const Breadcrumb = ({ items }: BreadcrumbProps) => { + return ( + + ); +}; diff --git a/apps/landing/src/components/docs/shared/CodeBlock.tsx b/apps/landing/src/components/docs/shared/CodeBlock.tsx new file mode 100644 index 0000000..c345843 --- /dev/null +++ b/apps/landing/src/components/docs/shared/CodeBlock.tsx @@ -0,0 +1,69 @@ +'use client'; + +/** + * CodeBlock Component + * + * Wrapper for displaying syntax-highlighted code blocks in documentation. + * Uses the existing Banatie design pattern from the landing page. + * + * Design Features: + * - MacOS-style window with traffic light dots + * - Dark slate background with backdrop blur + * - Copy button in top-right + * - Scrollable code area + * - Optional language label + */ + +import { useState } from 'react'; + +interface CodeBlockProps { + code: string; + language?: string; + filename?: string; + showLineNumbers?: boolean; +} + +export const CodeBlock = ({ + code, + language = 'bash', + filename, + showLineNumbers = false, +}: CodeBlockProps) => { + const [copied, setCopied] = useState(false); + + const handleCopy = () => { + navigator.clipboard.writeText(code); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( +
+ {/* Header with traffic lights and copy button */} +
+
+
+
+
+
+
+ {(filename || language) && ( + {filename || language} + )} +
+ +
+ + {/* Code content */} +
+        {code}
+      
+
+ ); +}; diff --git a/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx b/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx new file mode 100644 index 0000000..e57a428 --- /dev/null +++ b/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx @@ -0,0 +1,173 @@ +'use client'; + +/** + * Code Block Expanded Modal Component + * + * Full-screen code viewer for better readability + * Features: + * - Full-screen overlay with dark backdrop + * - Centered modal with max-width constraint + * - Language tabs for switching between languages + * - Close button (X) in top-right + * - Escape key support + * - Larger code text in expanded mode + * - Copy button with feedback + * - Language badge + * + * Usage: + * setIsOpen(false)} + * codes={{ curl: '...', javascript: '...', python: '...', go: '...' }} + * initialLanguage="curl" + * filename="example.js" + * /> + */ + +import { useState, useEffect } from 'react'; + +type Language = 'curl' | 'javascript' | 'python' | 'go'; + +interface CodeBlockExpandedProps { + isOpen: boolean; + onClose: () => void; + codes: Record; + initialLanguage: Language; + filename?: string; +} + +export const CodeBlockExpanded = ({ + isOpen, + onClose, + codes, + initialLanguage, + filename, +}: CodeBlockExpandedProps) => { + const [currentLanguage, setCurrentLanguage] = useState(initialLanguage); + const [copied, setCopied] = useState(false); + + // Update language when modal opens + useEffect(() => { + if (isOpen) { + setCurrentLanguage(initialLanguage); + } + }, [isOpen, initialLanguage]); + + // Handle escape key + useEffect(() => { + const handleEscape = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + onClose(); + } + }; + + if (isOpen) { + document.addEventListener('keydown', handleEscape); + // Prevent body scroll when modal is open + document.body.style.overflow = 'hidden'; + } + + return () => { + document.removeEventListener('keydown', handleEscape); + document.body.style.overflow = 'unset'; + }; + }, [isOpen, onClose]); + + // Copy to clipboard + const copyCode = () => { + navigator.clipboard.writeText(codes[currentLanguage]); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + if (!isOpen) return null; + + return ( +
+ {/* Modal Content */} +
e.stopPropagation()} + > + {/* Header */} +
+ {/* Left: Language Tabs */} +
+ Language: +
+ {(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang) => ( + + ))} +
+
+ + {/* Right: Actions */} +
+ {/* Copy Button */} + + + {/* Close Button */} + +
+
+ + {/* Code Content - Larger text, better spacing */} +
+
+            {codes[currentLanguage]}
+          
+
+ + {/* Hint Text */} +
+

+ Press Esc to close +

+
+
+
+ ); +}; diff --git a/apps/landing/src/components/docs/shared/Table.tsx b/apps/landing/src/components/docs/shared/Table.tsx new file mode 100644 index 0000000..e50ade8 --- /dev/null +++ b/apps/landing/src/components/docs/shared/Table.tsx @@ -0,0 +1,93 @@ +'use client'; + +/** + * Enhanced Table Component + * + * Features: + * - Larger font: text-base for cells (more readable) + * - Better padding: py-4 px-6 (spacious) + * - Full-width with proper column distribution + * - Hover states for rows + * - Responsive: horizontal scroll on mobile + * - Optional sortable headers (UI only, no logic yet) + * + * Usage: + *

+ */ + +import { ReactNode } from 'react'; + +interface TableProps { + headers: string[]; + rows: (string | ReactNode)[][]; + sortable?: boolean; +} + +export const Table = ({ headers, rows, sortable = false }: TableProps) => { + return ( +
+
+ {/* Header */} + + + {headers.map((header, idx) => ( + + ))} + + + + {/* Body */} + + {rows.map((row, rowIdx) => ( + + {row.map((cell, cellIdx) => ( + + ))} + + ))} + +
+
+ {header} + {sortable && ( + + )} +
+
+ {cell} +
+ + ); +}; diff --git a/apps/landing/src/components/docs/shared/TipBox.tsx b/apps/landing/src/components/docs/shared/TipBox.tsx new file mode 100644 index 0000000..0ff884b --- /dev/null +++ b/apps/landing/src/components/docs/shared/TipBox.tsx @@ -0,0 +1,90 @@ +'use client'; + +/** + * TipBox Component - Dual Style System + * + * Provides two distinct styles for callouts/notes: + * + * 1. Compact Style (Variant A inspired): + * - Small emoji icon on left + * - Compact padding (p-4) + * - Smaller text (text-sm) + * - Subtle background with thin border + * - Best for minor notes and tips + * + * 2. Prominent Style (Adapted from Variant C): + * - NO icon + * - Larger padding (p-6) + * - Larger text (text-base) + * - Gradient border with soft glow + * - More visual weight + * - Best for important warnings and security notices + * + * Usage: + * + * This is a compact tip + * + * + * + * This is an important security warning + * + */ + +import { ReactNode } from 'react'; + +type TipType = 'info' | 'warning' | 'success'; +type TipVariant = 'compact' | 'prominent'; + +interface TipBoxProps { + children: ReactNode; + variant?: TipVariant; + type?: TipType; +} + +const icons: Record = { + info: '💡', + warning: '⚠️', + success: '✓', +}; + +const compactStyles: Record = { + info: 'bg-purple-500/10 border-purple-500/20 text-purple-300', + warning: 'bg-amber-500/10 border-amber-500/20 text-amber-300', + success: 'bg-green-500/10 border-green-500/20 text-green-300', +}; + +const prominentStyles: Record = { + info: 'bg-gradient-to-br from-purple-500/5 via-cyan-500/5 to-purple-500/5 border-purple-500/30 text-gray-300 shadow-lg shadow-purple-500/10', + warning: 'bg-gradient-to-br from-amber-500/5 via-orange-500/5 to-amber-500/5 border-amber-500/30 text-gray-300 shadow-lg shadow-amber-500/10', + success: 'bg-gradient-to-br from-green-500/5 via-emerald-500/5 to-green-500/5 border-green-500/30 text-gray-300 shadow-lg shadow-green-500/10', +}; + +export const TipBox = ({ children, variant = 'compact', type = 'info' }: TipBoxProps) => { + const isCompact = variant === 'compact'; + const icon = icons[type]; + const styleClass = isCompact ? compactStyles[type] : prominentStyles[type]; + + if (isCompact) { + return ( +
+ {icon} +
{children}
+
+ ); + } + + // Prominent style + return ( +
+
{children}
+
+ ); +}; diff --git a/apps/landing/src/components/layout/ThreeColumnLayout.tsx b/apps/landing/src/components/layout/ThreeColumnLayout.tsx new file mode 100644 index 0000000..4a0c01e --- /dev/null +++ b/apps/landing/src/components/layout/ThreeColumnLayout.tsx @@ -0,0 +1,119 @@ +'use client'; + +/** + * Three Column Layout - Core Wireframe Component + * + * Provides a consistent three-column layout structure used across the application. + * This is the single source of truth for column widths, breakpoints, and responsive behavior. + * + * Column Structure: + * - Left: w-64 (256px), hidden until lg breakpoint + * - Center: flex-1 (flexible, takes remaining space) + * - Right: w-56 (224px), hidden until xl breakpoint + * + * Usage Examples: + * + * 1. SubsectionNav (3 columns): + * } + * center={} + * right={} + * /> + * + * 2. Docs Layout (2 columns - left + center): + * } + * center={} + * /> + * + * 3. Doc Page (2 columns - center + right): + * } + * right={} + * /> + * + * Design Principles: + * - Responsive breakpoints match Tailwind defaults (lg: 1024px, xl: 1280px) + * - Column widths ensure visual alignment across all usage contexts + * - Flexible center column adapts to available space + * - Optional columns enable 1, 2, or 3 column layouts + */ + +import { ReactNode } from 'react'; + +/** + * Props for ThreeColumnLayout component + */ +export interface ThreeColumnLayoutProps { + /** Left column content (w-64, hidden until lg breakpoint) */ + left?: ReactNode; + + /** Center column content (flex-1, always visible) */ + center: ReactNode; + + /** Right column content (w-56, hidden until xl breakpoint) */ + right?: ReactNode; + + /** Additional classes for left column */ + leftClassName?: string; + + /** Additional classes for center column */ + centerClassName?: string; + + /** Additional classes for right column */ + rightClassName?: string; + + /** Additional classes for container */ + containerClassName?: string; + + /** Breakpoint for showing left column (default: 'lg') */ + leftBreakpoint?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'; + + /** Breakpoint for showing right column (default: 'xl') */ + rightBreakpoint?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'; +} + +/** + * Three Column Layout Component + * + * Core wireframe for consistent three-column layouts across the application. + * Handles responsive behavior and provides customization via className props. + */ +export const ThreeColumnLayout = ({ + left, + center, + right, + leftClassName = '', + centerClassName = '', + rightClassName = '', + containerClassName = '', + leftBreakpoint = 'lg', + rightBreakpoint = 'xl', +}: ThreeColumnLayoutProps) => { + // Generate responsive visibility classes + const leftHidden = `hidden ${leftBreakpoint}:block`; + const rightHidden = `hidden ${rightBreakpoint}:block`; + + return ( +
+ {/* Left Column - w-64 (256px) */} + {left && ( +
+ {left} +
+ )} + + {/* Center Column - flex-1 (flexible) */} +
+ {center} +
+ + {/* Right Column - w-56 (224px) */} + {right && ( +
+ {right} +
+ )} +
+ ); +}; diff --git a/apps/landing/src/components/shared/SubsectionNav.tsx b/apps/landing/src/components/shared/SubsectionNav.tsx new file mode 100644 index 0000000..33ce3aa --- /dev/null +++ b/apps/landing/src/components/shared/SubsectionNav.tsx @@ -0,0 +1,419 @@ +'use client'; + +/** + * Subsection Navigation Component + * + * Reusable navigation bar for documentation and other subsections + * Features: + * - Dark nav bar with decorative wave line + * - Active state indicator (purple color) + * - Optional API Key input on the right + * - Responsive (hamburger menu on mobile) + * - Three-column layout matching docs structure + * - Customizable left/right slots + * + * Uses ThreeColumnLayout for consistent alignment with docs pages. + * Columns align with docs layout at all screen widths. + * + * Usage: + * } + * rightSlot={} + * /> + */ + +import { useState, useEffect, useRef, ReactNode } from 'react'; +import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout'; + +interface NavItem { + label: string; + href: string; +} + +interface SubsectionNavProps { + items: NavItem[]; + currentPath: string; + ctaText?: string; + ctaHref?: string; + onCtaClick?: () => void; + showApiKeyInput?: boolean; + /** Optional content for left column (w-64, hidden until lg) */ + leftSlot?: ReactNode; + /** Optional content for right column (w-56, hidden until xl). If not provided and showApiKeyInput is true, API key input is used. */ + rightSlot?: ReactNode; +} + +const API_KEY_STORAGE = 'banatie_docs_api_key'; + +export const SubsectionNav = ({ + items, + currentPath, + showApiKeyInput = false, + leftSlot, + rightSlot, +}: SubsectionNavProps) => { + const [mobileMenuOpen, setMobileMenuOpen] = useState(false); + const [apiKey, setApiKey] = useState(''); + const [isApiKeyExpanded, setIsApiKeyExpanded] = useState(false); + const [keyVisible, setKeyVisible] = useState(false); + const dropdownRef = useRef(null); + + const isActive = (href: string) => currentPath.startsWith(href); + + // Load API key from localStorage + useEffect(() => { + if (showApiKeyInput) { + const stored = localStorage.getItem(API_KEY_STORAGE); + if (stored) setApiKey(stored); + } + }, [showApiKeyInput]); + + // Handle API key changes + const handleApiKeyChange = (value: string) => { + setApiKey(value); + if (value) { + localStorage.setItem(API_KEY_STORAGE, value); + } else { + localStorage.removeItem(API_KEY_STORAGE); + } + + // Dispatch event to notify widgets + window.dispatchEvent(new CustomEvent('apiKeyChanged', { detail: value })); + }; + + // Handle clear API key + const handleClear = () => { + setApiKey(''); + localStorage.removeItem(API_KEY_STORAGE); + window.dispatchEvent(new CustomEvent('apiKeyChanged', { detail: '' })); + }; + + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsApiKeyExpanded(false); + } + }; + + if (isApiKeyExpanded) { + document.addEventListener('mousedown', handleClickOutside); + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isApiKeyExpanded]); + + // Listen for custom event to expand API key from widgets + useEffect(() => { + const handleExpandApiKey = () => { + setIsApiKeyExpanded(true); + // Scroll to top to show nav + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + window.addEventListener('expandApiKeyInput', handleExpandApiKey); + + return () => { + window.removeEventListener('expandApiKeyInput', handleExpandApiKey); + }; + }, []); + + // Desktop API Key Input Component + const apiKeyComponent = showApiKeyInput && ( +
+ + + {/* Dropdown Card */} + {isApiKeyExpanded && ( +
+
+
+

API Key

+

+ Enter once, use across all examples +

+
+ +
+ +
+ +
+ handleApiKeyChange(e.target.value)} + placeholder="Enter your API key" + className="flex-1 px-3 py-2 bg-slate-800 border border-slate-700 focus:border-purple-500 focus:ring-1 focus:ring-purple-500 rounded-lg text-sm text-gray-300 font-mono placeholder-gray-500 focus:outline-none transition-colors" + /> + +
+ + {apiKey && ( + + )} +
+ +
+

Stored locally in your browser

+
+
+ )} +
+ ); + + return ( + + ); +};