banatie-service/apps/landing/src/components/docs/shared/CodeBlockExpanded.tsx

174 lines
5.3 KiB
TypeScript

'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
* - Language tabs for switching between languages
* - Close button (X) in top-right
* - Escape key support
* - Larger code text in expanded mode
* - Copy button with feedback
* - Language badge
*
* Usage:
* <CodeBlockExpanded
* isOpen={isOpen}
* onClose={() => setIsOpen(false)}
* codes={{ curl: '...', javascript: '...', python: '...', go: '...' }}
* initialLanguage="curl"
* filename="example.js"
* />
*/
import { useState, useEffect } from 'react';
type Language = 'curl' | 'javascript' | 'python' | 'go';
interface CodeBlockExpandedProps {
isOpen: boolean;
onClose: () => void;
codes: Record<Language, string>;
initialLanguage: Language;
filename?: string;
}
export const CodeBlockExpanded = ({
isOpen,
onClose,
codes,
initialLanguage,
filename,
}: CodeBlockExpandedProps) => {
const [currentLanguage, setCurrentLanguage] = useState<Language>(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) => {
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(codes[currentLanguage]);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
if (!isOpen) return null;
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/80 backdrop-blur-sm"
onClick={onClose}
role="dialog"
aria-modal="true"
aria-label="Expanded code view"
>
{/* Modal Content */}
<div
className="relative w-full max-w-7xl max-h-[90vh] overflow-hidden rounded-2xl bg-slate-950 border border-slate-700 shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="flex items-center justify-between px-6 py-4 border-b border-slate-700 bg-slate-900/80">
{/* Left: Language Tabs */}
<div className="flex items-center gap-3">
<span className="text-sm font-medium text-gray-400 mr-2">Language:</span>
<div className="flex gap-2">
{(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang) => (
<button
key={lang}
onClick={() => setCurrentLanguage(lang)}
className={`px-3 py-1.5 text-xs rounded-lg transition-colors ${
currentLanguage === lang
? 'bg-purple-500/20 text-purple-300 font-semibold'
: 'text-gray-400 hover:text-white hover:bg-slate-800'
}`}
>
{lang === 'javascript' ? 'JavaScript' : lang.charAt(0).toUpperCase() + lang.slice(1)}
</button>
))}
</div>
</div>
{/* Right: Actions */}
<div className="flex items-center gap-2">
{/* Copy Button */}
<button
onClick={copyCode}
className={`px-4 py-1.5 text-xs rounded-lg transition-colors ${
copied
? 'bg-green-500/20 text-green-400'
: 'bg-purple-600/20 hover:bg-purple-600/30 text-purple-400'
}`}
>
{copied ? '✓ Copied!' : 'Copy'}
</button>
{/* Close Button */}
<button
onClick={onClose}
className="p-2 text-gray-400 hover:text-white transition-colors rounded-lg hover:bg-slate-800"
aria-label="Close expanded view"
>
<svg
className="w-5 h-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div>
{/* Code Content - Larger text, better spacing */}
<div className="overflow-auto max-h-[calc(90vh-6rem)] p-8 bg-slate-950/50">
<pre className="text-base text-gray-300 leading-relaxed">
<code>{codes[currentLanguage]}</code>
</pre>
</div>
{/* Hint Text */}
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 px-3 py-1.5 bg-slate-900/90 border border-slate-700 rounded-full">
<p className="text-xs text-gray-400">
Press <kbd className="px-1.5 py-0.5 bg-slate-800 rounded text-purple-400">Esc</kbd> to close
</p>
</div>
</div>
</div>
);
};