diff --git a/apps/landing/src/app/docs/layout.tsx b/apps/landing/src/app/docs/layout.tsx
index 69e1d52..67e1f43 100644
--- a/apps/landing/src/app/docs/layout.tsx
+++ b/apps/landing/src/app/docs/layout.tsx
@@ -5,6 +5,7 @@ import { usePathname } from 'next/navigation';
import { SubsectionNav } from '@/components/shared/SubsectionNav';
import { DocsSidebar } from '@/components/docs/layout/DocsSidebar';
import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout';
+import { ApiKeyWidget } from '@/components/shared/ApiKeyWidget/apikey-widget';
/**
* Root Documentation Layout
@@ -57,6 +58,7 @@ export default function DocsRootLayout({ children }: DocsRootLayoutProps) {
currentPath={pathname}
ctaText="Join Beta"
ctaHref="/signup"
+ rightSlot={}
/>
{/* Three-column Documentation Layout */}
diff --git a/apps/landing/src/components/shared/ApiKeyWidget/apikey-context.tsx b/apps/landing/src/components/shared/ApiKeyWidget/apikey-context.tsx
new file mode 100644
index 0000000..bc8f795
--- /dev/null
+++ b/apps/landing/src/components/shared/ApiKeyWidget/apikey-context.tsx
@@ -0,0 +1,17 @@
+/*
+
+TODO: create ApiKeyProvider and useApiKey hook to access provider values
+
+usage example: const { organizationSlug, projectSlug, apiKey, onRevoke } = useApiKey();
+
+see ApiKeyWidget component (src/components/shared/ApiKeyWidget/apikey-widget.tsx)
+
+the functionality should be strictly copied from src/app/demo/tti/page.tsx (see apikey related functionality) and MinimizedApiKey
+
+Move apikey simple actions in src/lib/apikey
+
+Provider should centralize apikey information and organize actions call from lib and then provide apikey related functionality down to children
+
+
+This is phase 1 of a task of centralizing apikey functionality that now is not DRY in demo pages
+*/
\ No newline at end of file
diff --git a/apps/landing/src/components/shared/ApiKeyWidget/apikey-widget.tsx b/apps/landing/src/components/shared/ApiKeyWidget/apikey-widget.tsx
index a4c3d41..4a49fe9 100644
--- a/apps/landing/src/components/shared/ApiKeyWidget/apikey-widget.tsx
+++ b/apps/landing/src/components/shared/ApiKeyWidget/apikey-widget.tsx
@@ -9,14 +9,10 @@ interface ApiKeyWidgetProps {
onRevoke: () => void;
}
-export function ApiKeyWidget({
- organizationSlug,
- projectSlug,
- apiKey,
- onRevoke,
-}: ApiKeyWidgetProps) {
+export function ApiKeyWidget() {
const [expanded, setExpanded] = useState(false);
const [keyVisible, setKeyVisible] = useState(false);
+ const { organizationSlug, projectSlug, apiKey, onRevoke } = useApiKey();
return (
diff --git a/apps/landing/src/components/shared/SubsectionNav.tsx b/apps/landing/src/components/shared/SubsectionNav.tsx
index 33ce3aa..b226bf5 100644
--- a/apps/landing/src/components/shared/SubsectionNav.tsx
+++ b/apps/landing/src/components/shared/SubsectionNav.tsx
@@ -7,7 +7,6 @@
* 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
@@ -19,13 +18,12 @@
*
}
* rightSlot={
}
* />
*/
-import { useState, useEffect, useRef, ReactNode } from 'react';
+import { useState, ReactNode } from 'react';
import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout';
interface NavItem {
@@ -39,210 +37,17 @@ interface SubsectionNavProps {
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. */
+ /** Optional content for right column (w-56, hidden until xl) */
rightSlot?: ReactNode;
}
-const API_KEY_STORAGE = 'banatie_docs_api_key';
-
-export const SubsectionNav = ({
- items,
- currentPath,
- showApiKeyInput = false,
- leftSlot,
- rightSlot,
-}: SubsectionNavProps) => {
+export const SubsectionNav = ({ items, currentPath, 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 (
}
- right={rightSlot || apiKeyComponent}
+ right={rightSlot}
/>
{/* Decorative Wave Line */}
@@ -352,65 +152,6 @@ export const SubsectionNav = ({
);
})}
-
- {/* API Key Input in Mobile Menu */}
- {showApiKeyInput && (
-
-
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
-
- )}
)}