From 658f1420db40d1b4e4449cd0e2d56f4e7dea90b2 Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Tue, 14 Oct 2025 01:07:50 +0700 Subject: [PATCH] feat: polish --- apps/landing/src/app/globals.css | 37 +++++ .../docs/final/DocsSidebarFinal.tsx | 2 +- .../docs/final/InteractiveAPIWidgetFinal.tsx | 127 ++++++++++++++++-- .../docs/shared/CodeBlockExpanded.tsx | 75 ++++++++--- .../src/components/shared/SubsectionNav.tsx | 28 +--- 5 files changed, 210 insertions(+), 59 deletions(-) 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/final/DocsSidebarFinal.tsx b/apps/landing/src/components/docs/final/DocsSidebarFinal.tsx index e7fe7c9..7c4e60c 100644 --- a/apps/landing/src/components/docs/final/DocsSidebarFinal.tsx +++ b/apps/landing/src/components/docs/final/DocsSidebarFinal.tsx @@ -146,7 +146,7 @@ export const DocsSidebarFinal = ({ currentPath }: DocsSidebarFinalProps) => { = {}; + // Initialize with proper defaults + const defaults: Record = { + prompt: 'a futuristic city at sunset', + filename: 'demo', + aspectRatio: '16:9', + }; + + // Override with parameter defaults if provided parameters.forEach((param) => { if (param.defaultValue) { defaults[param.name] = param.defaultValue; } }); + setParamValues(defaults); }, [parameters]); @@ -162,6 +169,80 @@ func main() { } }; + // Generate all language codes at once + const generateAllCodes = (): Record => { + const url = `${API_BASE_URL}${endpoint}`; + + return { + curl: `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" + }'`, + + javascript: `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);`, + + python: `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())`, + + go: `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() +}`, + }; + }; + // Execute API request const executeRequest = async () => { if (!apiKey) { @@ -171,13 +252,21 @@ func main() { setIsExecuting(true); setError(null); + setResponse(null); try { - const body: Record = {}; - parameters.forEach((param) => { - if (paramValues[param.name]) { - body[param.name] = paramValues[param.name]; - } + // Build proper request body + 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}`, { @@ -189,10 +278,27 @@ func main() { body: method !== 'GET' ? JSON.stringify(body) : undefined, }); + console.log('🟢 Response Status:', res.status, res.statusText); + + // Handle non-OK responses + 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) { - setError(err instanceof Error ? err.message : 'Failed to execute request'); + console.error('❌ API Error:', err); + const errorMsg = err instanceof Error ? err.message : 'Failed to execute request'; + setError(`Request failed: ${errorMsg}`); } finally { setIsExecuting(false); } @@ -339,9 +445,8 @@ func main() { setIsExpanded(false)} - code={generateCode()} - language={language} - filename={`example.${language === 'javascript' ? 'js' : language === 'python' ? 'py' : language}`} + codes={generateAllCodes()} + initialLanguage={language} /> ); diff --git a/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx b/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx index 8f28869..e57a428 100644 --- a/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx +++ b/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx @@ -7,39 +7,52 @@ * 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 still visible + * - Copy button with feedback * - Language badge * * Usage: * setIsOpen(false)} - * code={codeString} - * language="javascript" + * codes={{ curl: '...', javascript: '...', python: '...', go: '...' }} + * initialLanguage="curl" * filename="example.js" * /> */ -import { useEffect } from 'react'; +import { useState, useEffect } from 'react'; + +type Language = 'curl' | 'javascript' | 'python' | 'go'; interface CodeBlockExpandedProps { isOpen: boolean; onClose: () => void; - code: string; - language: string; + codes: Record; + initialLanguage: Language; filename?: string; } export const CodeBlockExpanded = ({ isOpen, onClose, - code, - language, + 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) => { @@ -62,7 +75,9 @@ export const CodeBlockExpanded = ({ // Copy to clipboard const copyCode = () => { - navigator.clipboard.writeText(code); + navigator.clipboard.writeText(codes[currentLanguage]); + setCopied(true); + setTimeout(() => setCopied(false), 2000); }; if (!isOpen) return null; @@ -77,27 +92,43 @@ export const CodeBlockExpanded = ({ > {/* Modal Content */}
e.stopPropagation()} > {/* Header */}
+ {/* Left: Language Tabs */}
- {filename && ( - {filename} - )} - - {language} - + Language: +
+ {(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang) => ( + + ))} +
+ {/* Right: Actions */}
{/* Copy Button */} {/* Close Button */} @@ -123,10 +154,10 @@ export const CodeBlockExpanded = ({
- {/* Code Content */} -
-
-            {code}
+        {/* Code Content - Larger text, better spacing */}
+        
+
+            {codes[currentLanguage]}
           
diff --git a/apps/landing/src/components/shared/SubsectionNav.tsx b/apps/landing/src/components/shared/SubsectionNav.tsx index 1ae7314..edb1485 100644 --- a/apps/landing/src/components/shared/SubsectionNav.tsx +++ b/apps/landing/src/components/shared/SubsectionNav.tsx @@ -50,7 +50,7 @@ export const SubsectionNav = ({