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"
- />
+ {/* Minimized Widget */}
+
+ {/* Header */}
+
+
+
+ {method}
+
{endpoint}
-
-
- {/* Language Tabs with Expand Button */}
-
-
- {(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang) => (
-
- ))}
-
-
-
-
-
-
-
- {/* Code Display */}
-
-
- {/* Try It Button */}
-
- {/* Response Section - Enhanced with success/error styling */}
+ {/* Code Section - Full Width */}
+
+ {/* Language Tabs */}
+
+ {(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang, idx) => {
+ const colors = ['purple', 'cyan', 'amber', 'purple'];
+ const color = colors[idx];
+ return (
+
+ );
+ })}
+
+
+ {/* Code Display */}
+
+
+ Code Example
+
+
+
+
+
+
+ {/* Footer */}
+
+
+
+
+
+ {/* Inline Response (if any) */}
{(response || error) && (
-
-
-
Response
- {error ? (
- // Error Response
-
-
-
- ✗ Error
-
+
+
+ 📦
+ Response
+
+ {error ? (
+
+
- ) : isSuccess ? (
- // Success Response
-
-
-
+
+ ) : (
+
+ {isSuccess && (
+
+
✓ 200 Success
-
- {renderResponse(response)}
-
-
- ) : (
- // Normal Response
-
- {renderResponse(response)}
+ )}
+
+ {JSON.stringify(response, null, 2)}
- )}
-
+
+ )}
)}
- {/* Expanded Code Modal */}
-
setIsExpanded(false)}
- codes={generateAllCodes()}
- initialLanguage={language}
- />
+ {/* Expanded Modal */}
+ {isExpanded && (
+
+
+ {/* Modal Header */}
+
+
+
+ {method}
+
+
{endpoint}
+
+
+
+
+ {/* Two-Panel Layout */}
+
+ {/* Left: Code */}
+
+
+ {(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang, idx) => {
+ const colors = ['purple', 'cyan', 'amber', 'purple'];
+ const color = colors[idx];
+ return (
+
+ );
+ })}
+
+
+
+
+ Code Example
+
+
+
+
+
+
+ {/* Right: Response */}
+
+
+ 📦
+ Response
+
+
+
+
+ {response && (
+
+ {response.success ? '✓ Success' : '✕ Error'}
+
+ )}
+
+
+ {error ? (
+
+ ) : response ? (
+
+ {JSON.stringify(response, null, 2)}
+
+ ) : (
+
+
+
🚀
+
+ Click "Try It" below to see the response
+
+
+
+ )}
+
+
+
+ {/* Try It Button in Expanded View */}
+
+
+
+
+ {/* Footer hint */}
+
+
+
+ )}
>
);
};
diff --git a/apps/landing/src/components/shared/SubsectionNav.tsx b/apps/landing/src/components/shared/SubsectionNav.tsx
index edb1485..f3800a9 100644
--- a/apps/landing/src/components/shared/SubsectionNav.tsx
+++ b/apps/landing/src/components/shared/SubsectionNav.tsx
@@ -6,8 +6,8 @@
* 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
+ * - Active state indicator (purple color)
+ * - Optional API Key input on the right
* - Responsive (hamburger menu on mobile)
* - Can be reused across landing app sections
*
@@ -15,12 +15,11 @@
*
*/
-import { useState } from 'react';
+import { useState, useEffect, useRef } from 'react';
interface NavItem {
label: string;
@@ -33,24 +32,89 @@ interface SubsectionNavProps {
ctaText?: string;
ctaHref?: string;
onCtaClick?: () => void;
+ showApiKeyInput?: boolean;
}
+const API_KEY_STORAGE = 'banatie_docs_api_key';
+
export const SubsectionNav = ({
items,
currentPath,
- ctaText = 'Join Beta',
- ctaHref = '/signup',
- onCtaClick,
+ showApiKeyInput = false,
}: 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);
+ };
+ }, []);
+
return (