From 1d1a88d07357b9eb0bd59d19e6ef8da1c94f7588 Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Tue, 14 Oct 2025 00:54:34 +0700 Subject: [PATCH] feat: final variant ready --- .../app/docs/final/api/text-to-image/page.tsx | 255 +++++++++++++ .../docs/final/guides/authentication/page.tsx | 336 +++++++++++++++++ apps/landing/src/app/docs/final/page.tsx | 225 +++++++++++ apps/landing/src/app/docs/page.tsx | 107 ++++++ .../components/docs/final/DocsLayoutFinal.tsx | 64 ++++ .../docs/final/DocsSidebarFinal.tsx | 181 +++++++++ .../components/docs/final/DocsTOCFinal.tsx | 102 +++++ .../docs/final/InteractiveAPIWidgetFinal.tsx | 348 ++++++++++++++++++ .../docs/shared/CodeBlockExpanded.tsx | 142 +++++++ .../src/components/docs/shared/Table.tsx | 93 +++++ .../src/components/docs/shared/TipBox.tsx | 90 +++++ .../src/components/shared/SubsectionNav.tsx | 179 +++++++++ 12 files changed, 2122 insertions(+) create mode 100644 apps/landing/src/app/docs/final/api/text-to-image/page.tsx create mode 100644 apps/landing/src/app/docs/final/guides/authentication/page.tsx create mode 100644 apps/landing/src/app/docs/final/page.tsx create mode 100644 apps/landing/src/components/docs/final/DocsLayoutFinal.tsx create mode 100644 apps/landing/src/components/docs/final/DocsSidebarFinal.tsx create mode 100644 apps/landing/src/components/docs/final/DocsTOCFinal.tsx create mode 100644 apps/landing/src/components/docs/final/InteractiveAPIWidgetFinal.tsx create mode 100644 apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx create mode 100644 apps/landing/src/components/docs/shared/Table.tsx create mode 100644 apps/landing/src/components/docs/shared/TipBox.tsx create mode 100644 apps/landing/src/components/shared/SubsectionNav.tsx 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 */} +
+

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 */} +
+

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 ( + + ); +}; 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 ( + + ); +}; 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) => ( + + ))} +
+
+ + +
+
+ + {/* Code Display */} +
+
+            {generateCode()}
+          
+
+ + {/* Try It Button */} +
+ +
+ + {/* 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 */} + + + {/* Close Button */} + +
+
+ + {/* Code Content */} +
+
+            {code}
+          
+
+ + {/* 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/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 ( + + ); +};