diff --git a/apps/landing/src/app/docs/final/api/text-to-image/page.tsx b/apps/landing/src/app/docs/final/api/text-to-image/page.tsx
new file mode 100644
index 0000000..7c1ef9e
--- /dev/null
+++ b/apps/landing/src/app/docs/final/api/text-to-image/page.tsx
@@ -0,0 +1,255 @@
+'use client';
+
+/**
+ * API Reference: Text to Image - Final Variant
+ *
+ * Features:
+ * - SubsectionNav at top
+ * - InteractiveAPIWidgetFinal with expand + success styling
+ * - Enhanced tables for parameters and error codes
+ * - Compact TipBox for parameter descriptions
+ * - Simplified Next Steps
+ */
+
+import { DocsLayoutFinal } from '@/components/docs/final/DocsLayoutFinal';
+import { DocsSidebarFinal } from '@/components/docs/final/DocsSidebarFinal';
+import { DocsTOCFinal } from '@/components/docs/final/DocsTOCFinal';
+import { SubsectionNav } from '@/components/shared/SubsectionNav';
+import { TipBox } from '@/components/docs/shared/TipBox';
+import { Table } from '@/components/docs/shared/Table';
+import { InteractiveAPIWidgetFinal } from '@/components/docs/final/InteractiveAPIWidgetFinal';
+import { Breadcrumb } from '@/components/docs/shared/Breadcrumb';
+import { CodeBlock } from '@/components/docs/shared/CodeBlock';
+
+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 navItems = [
+ { label: 'Documentation', href: '/docs/final' },
+ { label: 'Demo', href: '/demo' },
+ { label: 'Examples', href: '/docs/final/examples' },
+];
+
+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 (
+ <>
+ {/* Subsection Navigation */}
+
+
+ }
+ toc={ }
+ >
+
+
+ {/* Hero Section */}
+
+
Text to Image
+
+ Generate high-quality images from text prompts using AI-powered models.
+
+
+
+ {/* 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
+
+
+
+ POST
+
+ /api/text-to-image
+
+
+ Base URL: https://api.banatie.com
+
+
+
+
+ {/* 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.
+
+
+
+
+
+ {/* Next Steps */}
+
+
+ >
+ );
+}
diff --git a/apps/landing/src/app/docs/final/guides/authentication/page.tsx b/apps/landing/src/app/docs/final/guides/authentication/page.tsx
new file mode 100644
index 0000000..224aaf3
--- /dev/null
+++ b/apps/landing/src/app/docs/final/guides/authentication/page.tsx
@@ -0,0 +1,336 @@
+'use client';
+
+/**
+ * Authentication Guide - Final Variant
+ *
+ * Features:
+ * - SubsectionNav at top
+ * - Prominent TipBox for security warnings
+ * - Compact TipBox for general tips
+ * - Enhanced tables for rate limits and key types
+ * - Simplified Next Steps
+ */
+
+import { DocsLayoutFinal } from '@/components/docs/final/DocsLayoutFinal';
+import { DocsSidebarFinal } from '@/components/docs/final/DocsSidebarFinal';
+import { DocsTOCFinal } from '@/components/docs/final/DocsTOCFinal';
+import { SubsectionNav } from '@/components/shared/SubsectionNav';
+import { TipBox } from '@/components/docs/shared/TipBox';
+import { Table } from '@/components/docs/shared/Table';
+import { Breadcrumb } from '@/components/docs/shared/Breadcrumb';
+import { CodeBlock } from '@/components/docs/shared/CodeBlock';
+
+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 },
+];
+
+const navItems = [
+ { label: 'Documentation', href: '/docs/final' },
+ { label: 'Demo', href: '/demo' },
+ { label: 'Examples', href: '/docs/final/examples' },
+];
+
+export default function AuthenticationGuidePage() {
+ return (
+ <>
+ {/* Subsection Navigation */}
+
+
+ }
+ toc={ }
+ >
+
+
+ {/* Hero Section */}
+
+
Authentication
+
+ Learn how to authenticate with the Banatie API using API keys, manage rate limits, and
+ implement security best practices.
+
+
+
+ {/* 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
+
+
+
+
+ {/* Next Steps */}
+
+
+ >
+ );
+}
diff --git a/apps/landing/src/app/docs/final/page.tsx b/apps/landing/src/app/docs/final/page.tsx
new file mode 100644
index 0000000..521d23b
--- /dev/null
+++ b/apps/landing/src/app/docs/final/page.tsx
@@ -0,0 +1,225 @@
+'use client';
+
+/**
+ * Getting Started Page - Final Variant
+ *
+ * Production-ready documentation landing page
+ * Features:
+ * - SubsectionNav at top
+ * - Both TipBox styles (compact + prominent)
+ * - Enhanced tables
+ * - Simplified Next Steps (2 cards only)
+ * - Clean, accessible design
+ */
+
+import { DocsLayoutFinal } from '@/components/docs/final/DocsLayoutFinal';
+import { DocsSidebarFinal } from '@/components/docs/final/DocsSidebarFinal';
+import { DocsTOCFinal } from '@/components/docs/final/DocsTOCFinal';
+import { SubsectionNav } from '@/components/shared/SubsectionNav';
+import { TipBox } from '@/components/docs/shared/TipBox';
+import { Table } from '@/components/docs/shared/Table';
+import { Breadcrumb } from '@/components/docs/shared/Breadcrumb';
+import { CodeBlock } from '@/components/docs/shared/CodeBlock';
+
+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 },
+];
+
+const navItems = [
+ { label: 'Documentation', href: '/docs/final' },
+ { label: 'Demo', href: '/demo' },
+ { label: 'Examples', href: '/docs/final/examples' },
+];
+
+export default function GettingStartedPageFinal() {
+ return (
+ <>
+ {/* Subsection Navigation */}
+
+
+ }
+ toc={ }
+ >
+
+
+ {/* Hero Section */}
+
+
Getting Started
+
+ Welcome to the Banatie API documentation. Learn how to integrate AI-powered image
+ generation into your applications in minutes.
+
+
+
+ {/* 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:
+
+
+
+ ✓ 200 Success
+
+
+
+ {`{
+ "success": true,
+ "data": {
+ "url": "https://cdn.banatie.com/org/project/generated/2025-01/mountain_sunset.png",
+ "filepath": "org/project/generated/2025-01/mountain_sunset.png",
+ "width": 1920,
+ "height": 1080,
+ "promptEnhancement": {
+ "enhancedPrompt": "A breathtaking mountain landscape..."
+ }
+ }
+}`}
+
+
+
+
+
+ {/* Next Steps - Simplified to 2 Cards */}
+
+ Next Steps
+
+ Now that you have generated your first image, explore these resources to build more advanced integrations:
+
+
+
+
+
+ >
+ );
+}
diff --git a/apps/landing/src/app/docs/page.tsx b/apps/landing/src/app/docs/page.tsx
index 34fdbce..b229630 100644
--- a/apps/landing/src/app/docs/page.tsx
+++ b/apps/landing/src/app/docs/page.tsx
@@ -53,6 +53,113 @@ export default function DocsIndexPage() {
+ {/* Final Variant - Recommended */}
+
+
+ {/* Other Variants for Reference */}
+
+
Other Variants (Reference)
+
+ Explore the original variants that inspired the final design
+
+
+
{/* Variant Cards */}
{/* Variant A: Clean & Minimal */}
diff --git a/apps/landing/src/components/docs/final/DocsLayoutFinal.tsx b/apps/landing/src/components/docs/final/DocsLayoutFinal.tsx
new file mode 100644
index 0000000..db66cc7
--- /dev/null
+++ b/apps/landing/src/components/docs/final/DocsLayoutFinal.tsx
@@ -0,0 +1,64 @@
+'use client';
+
+/**
+ * Documentation Layout - Final Variant
+ *
+ * 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 DocsLayoutFinalProps {
+ sidebar: ReactNode;
+ children: ReactNode;
+ toc: ReactNode;
+}
+
+export const DocsLayoutFinal = ({ sidebar, children, toc }: DocsLayoutFinalProps) => {
+ 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/final/DocsSidebarFinal.tsx b/apps/landing/src/components/docs/final/DocsSidebarFinal.tsx
new file mode 100644
index 0000000..e7fe7c9
--- /dev/null
+++ b/apps/landing/src/components/docs/final/DocsSidebarFinal.tsx
@@ -0,0 +1,181 @@
+'use client';
+
+/**
+ * Documentation Sidebar - Final Variant
+ *
+ * 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 DocsSidebarFinalProps {
+ currentPath: string;
+}
+
+const navigationItems: NavItem[] = [
+ {
+ label: 'Getting Started',
+ href: '/docs/final',
+ icon: '🚀',
+ },
+ {
+ label: 'API Reference',
+ href: '/docs/final/api',
+ icon: '📚',
+ children: [
+ { label: 'Text to Image', href: '/docs/final/api/text-to-image' },
+ { label: 'Upload', href: '/docs/final/api/upload' },
+ { label: 'Images', href: '/docs/final/api/images' },
+ ],
+ },
+ {
+ label: 'Guides',
+ href: '/docs/final/guides',
+ icon: '📖',
+ children: [
+ { label: 'Authentication', href: '/docs/final/guides/authentication' },
+ { label: 'Error Handling', href: '/docs/final/guides/error-handling' },
+ { label: 'Rate Limits', href: '/docs/final/guides/rate-limits' },
+ ],
+ },
+ {
+ label: 'Examples',
+ href: '/docs/final/examples',
+ icon: '💡',
+ },
+];
+
+export const DocsSidebarFinal = ({ currentPath }: DocsSidebarFinalProps) => {
+ 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 (
+
+ {/* Logo/Title */}
+
+
Documentation
+
Final: Production
+
+
+ {/* Navigation Items */}
+
+ {navigationItems.map((item) => {
+ const hasChildren = item.children && item.children.length > 0;
+ const expanded = isExpanded(item.label);
+ const active = isActive(item.href);
+
+ return (
+
+ {/* Parent Item */}
+
+
+ {/* Children Items - FIXED ACTIVE STATE */}
+ {hasChildren && expanded && (
+
+ {item.children!.map((child) => {
+ const childActive = isActive(child.href);
+ return (
+
+
+ {child.label}
+
+
+ );
+ })}
+
+ )}
+
+ );
+ })}
+
+
+ {/* Bottom Links */}
+
+
+ );
+};
diff --git a/apps/landing/src/components/docs/final/DocsTOCFinal.tsx b/apps/landing/src/components/docs/final/DocsTOCFinal.tsx
new file mode 100644
index 0000000..0a25277
--- /dev/null
+++ b/apps/landing/src/components/docs/final/DocsTOCFinal.tsx
@@ -0,0 +1,102 @@
+'use client';
+
+/**
+ * Table of Contents - Final Variant
+ *
+ * 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 DocsTOCFinalProps {
+ items: TocItem[];
+}
+
+export const DocsTOCFinal = ({ items }: DocsTOCFinalProps) => {
+ 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 (
+
+
+ On This Page
+
+
+
+ {items.map((item) => {
+ const isActive = activeId === item.id;
+ const isH3 = item.level === 3;
+
+ return (
+
+ scrollToSection(item.id)}
+ className={`
+ flex items-start gap-2 text-left w-full transition-colors group
+ ${isActive ? 'text-purple-400' : 'text-gray-500 hover:text-gray-300'}
+ `}
+ >
+ {/* Indicator dot */}
+
+ {item.text}
+
+
+ );
+ })}
+
+
+ );
+};
diff --git a/apps/landing/src/components/docs/final/InteractiveAPIWidgetFinal.tsx b/apps/landing/src/components/docs/final/InteractiveAPIWidgetFinal.tsx
new file mode 100644
index 0000000..8f45243
--- /dev/null
+++ b/apps/landing/src/components/docs/final/InteractiveAPIWidgetFinal.tsx
@@ -0,0 +1,348 @@
+'use client';
+
+/**
+ * Interactive API Widget - Final Variant
+ *
+ * Enhanced version of Variant A with:
+ * 1. Expand button for full-screen code view
+ * 2. Success response styling (green accent)
+ * 3. Error response styling (red accent)
+ * 4. Clickable image URLs in response
+ * 5. Status badges (200 Success, Error)
+ *
+ * Features:
+ * - Multi-language code tabs (curl, JavaScript, Python, Go)
+ * - API key input field (persists via localStorage)
+ * - "Try It" button to execute live requests
+ * - Response viewer with enhanced styling
+ * - Clean, focused design
+ */
+
+import { useState, useEffect } from 'react';
+import { CodeBlockExpanded } from '@/components/docs/shared/CodeBlockExpanded';
+
+interface InteractiveAPIWidgetFinalProps {
+ 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';
+
+const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000';
+const API_KEY_STORAGE = 'banatie_docs_api_key';
+
+export const InteractiveAPIWidgetFinal = ({
+ endpoint,
+ method,
+ description,
+ parameters = [],
+}: InteractiveAPIWidgetFinalProps) => {
+ 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);
+
+ // Parameter values
+ const [paramValues, setParamValues] = useState>({});
+
+ // Load API key from localStorage
+ useEffect(() => {
+ const stored = localStorage.getItem(API_KEY_STORAGE);
+ if (stored) setApiKey(stored);
+
+ // Initialize parameter default values
+ const defaults: Record = {};
+ parameters.forEach((param) => {
+ if (param.defaultValue) {
+ defaults[param.name] = param.defaultValue;
+ }
+ });
+ setParamValues(defaults);
+ }, [parameters]);
+
+ // Save API key to localStorage
+ const handleApiKeyChange = (value: string) => {
+ setApiKey(value);
+ if (value) {
+ localStorage.setItem(API_KEY_STORAGE, value);
+ } else {
+ localStorage.removeItem(API_KEY_STORAGE);
+ }
+ };
+
+ // Generate code examples
+ const generateCode = (): string => {
+ const url = `${API_BASE_URL}${endpoint}`;
+
+ 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"
+ "fmt"
+ "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');
+ return;
+ }
+
+ setIsExecuting(true);
+ setError(null);
+
+ try {
+ const body: Record = {};
+ parameters.forEach((param) => {
+ if (paramValues[param.name]) {
+ body[param.name] = paramValues[param.name];
+ }
+ });
+
+ 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,
+ });
+
+ const data = await res.json();
+ setResponse(data);
+ } catch (err) {
+ setError(err instanceof Error ? err.message : 'Failed to execute request');
+ } finally {
+ setIsExecuting(false);
+ }
+ };
+
+ // Copy code to clipboard
+ const copyCode = () => {
+ navigator.clipboard.writeText(generateCode());
+ };
+
+ // Render response with clickable URLs
+ const renderResponse = (data: any): string => {
+ return JSON.stringify(data, null, 2);
+ };
+
+ // Check if response is success
+ const isSuccess = response && response.success === true;
+
+ return (
+ <>
+
+ {/* Header with API Key Input */}
+
+
+
+
Try it out
+
{description}
+
+
+ handleApiKeyChange(e.target.value)}
+ placeholder="Enter your API key"
+ className="w-full px-3 py-2 text-xs bg-slate-800 border border-slate-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent"
+ />
+
+
+
+
+ {/* Language Tabs with Expand Button */}
+
+
+ {(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang) => (
+ setLanguage(lang)}
+ className={`px-3 py-1 text-xs rounded transition-colors ${
+ language === lang
+ ? 'bg-slate-700 text-white'
+ : 'text-gray-400 hover:text-white'
+ }`}
+ >
+ {lang === 'javascript' ? 'JavaScript' : lang.charAt(0).toUpperCase() + lang.slice(1)}
+
+ ))}
+
+
+
setIsExpanded(true)}
+ className="px-3 py-1 text-xs text-gray-400 hover:text-white transition-colors"
+ aria-label="Expand code view"
+ >
+
+
+
+
+
+ Copy
+
+
+
+
+ {/* Code Display */}
+
+
+ {/* Try It Button */}
+
+
+ {isExecuting ? 'Executing...' : 'Try It'}
+
+
+
+ {/* Response Section - Enhanced with success/error styling */}
+ {(response || error) && (
+
+
+
Response
+ {error ? (
+ // Error Response
+
+
+
+ ✗ Error
+
+
+
{error}
+
+ ) : isSuccess ? (
+ // Success Response
+
+
+
+ ✓ 200 Success
+
+
+
+ {renderResponse(response)}
+
+
+ ) : (
+ // Normal Response
+
+ {renderResponse(response)}
+
+ )}
+
+
+ )}
+
+
+ {/* Expanded Code Modal */}
+ setIsExpanded(false)}
+ code={generateCode()}
+ language={language}
+ filename={`example.${language === 'javascript' ? 'js' : language === 'python' ? 'py' : language}`}
+ />
+ >
+ );
+};
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..8f28869
--- /dev/null
+++ b/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx
@@ -0,0 +1,142 @@
+'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
+ * - Close button (X) in top-right
+ * - Escape key support
+ * - Larger code text in expanded mode
+ * - Copy button still visible
+ * - Language badge
+ *
+ * Usage:
+ * setIsOpen(false)}
+ * code={codeString}
+ * language="javascript"
+ * filename="example.js"
+ * />
+ */
+
+import { useEffect } from 'react';
+
+interface CodeBlockExpandedProps {
+ isOpen: boolean;
+ onClose: () => void;
+ code: string;
+ language: string;
+ filename?: string;
+}
+
+export const CodeBlockExpanded = ({
+ isOpen,
+ onClose,
+ code,
+ language,
+ filename,
+}: CodeBlockExpandedProps) => {
+ // 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(code);
+ };
+
+ if (!isOpen) return null;
+
+ return (
+
+ {/* Modal Content */}
+
e.stopPropagation()}
+ >
+ {/* Header */}
+
+
+ {filename && (
+ {filename}
+ )}
+
+ {language}
+
+
+
+
+ {/* Copy Button */}
+
+ Copy
+
+
+ {/* Close Button */}
+
+
+
+
+
+
+
+
+ {/* Code Content */}
+
+
+ {/* 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) => (
+
+
+ {header}
+ {sortable && (
+
+
+
+
+
+ )}
+
+
+ ))}
+
+
+
+ {/* Body */}
+
+ {rows.map((row, rowIdx) => (
+
+ {row.map((cell, cellIdx) => (
+
+ {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 (
+
+ );
+ }
+
+ // Prominent style
+ return (
+
+ );
+};
diff --git a/apps/landing/src/components/shared/SubsectionNav.tsx b/apps/landing/src/components/shared/SubsectionNav.tsx
new file mode 100644
index 0000000..1ae7314
--- /dev/null
+++ b/apps/landing/src/components/shared/SubsectionNav.tsx
@@ -0,0 +1,179 @@
+'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 underline/highlight)
+ * - "Join Beta" CTA button on the right
+ * - Responsive (hamburger menu on mobile)
+ * - Can be reused across landing app sections
+ *
+ * Usage:
+ *
+ */
+
+import { useState } from 'react';
+
+interface NavItem {
+ label: string;
+ href: string;
+}
+
+interface SubsectionNavProps {
+ items: NavItem[];
+ currentPath: string;
+ ctaText?: string;
+ ctaHref?: string;
+ onCtaClick?: () => void;
+}
+
+export const SubsectionNav = ({
+ items,
+ currentPath,
+ ctaText = 'Join Beta',
+ ctaHref = '/signup',
+ onCtaClick,
+}: SubsectionNavProps) => {
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
+
+ const isActive = (href: string) => currentPath.startsWith(href);
+
+ return (
+
+ {/* Main Nav Container */}
+
+
+ {/* Desktop Navigation */}
+
+
+ {/* CTA Button - Desktop */}
+
+
+ {/* Mobile Menu Button */}
+
+
+ {ctaText}
+
+
setMobileMenuOpen(!mobileMenuOpen)}
+ className="p-2 text-gray-400 hover:text-white transition-colors"
+ aria-label="Toggle menu"
+ >
+
+ {mobileMenuOpen ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ {/* Decorative Wave Line */}
+
+
+ {/* Mobile Menu Overlay */}
+ {mobileMenuOpen && (
+
+ )}
+
+ );
+};