feat(playground): add ExportCodeModal

This commit is contained in:
diegosouzapw
2026-05-28 11:20:13 -03:00
parent 331cc68e45
commit 58aa0b5040

View File

@@ -0,0 +1,157 @@
"use client";
// src/app/(dashboard)/dashboard/playground/components/ExportCodeModal.tsx
import { useState, useEffect, useCallback } from "react";
import type { PlaygroundState, ExportLanguage } from "@/lib/playground/codeExport";
import { exportAllLanguages, API_KEY_PLACEHOLDER } from "@/lib/playground/codeExport";
interface ExportCodeModalProps {
state: PlaygroundState;
onClose: () => void;
}
const LANGUAGE_TABS: Array<{ id: ExportLanguage; label: string }> = [
{ id: "curl", label: "curl" },
{ id: "python", label: "Python" },
{ id: "typescript", label: "TypeScript" },
];
/**
* ExportCodeModal — shows curl / Python / TypeScript snippets for the current playground state.
*
* Security: always uses API_KEY_PLACEHOLDER ("$OMNIROUTE_API_KEY") — never a real key (D11 / Hard Rule #1).
*/
export default function ExportCodeModal({ state, onClose }: ExportCodeModalProps) {
const [activeLanguage, setActiveLanguage] = useState<ExportLanguage>("curl");
const [copied, setCopied] = useState(false);
// Generate all snippets once (state is passed in from parent, not re-fetched).
const snippets = exportAllLanguages(state);
const currentCode = snippets[activeLanguage];
// Verify that no real API key is embedded (assertion — Hard Rule #1 / D11).
// The regex checks for typical API key patterns (sk-, or other 16+ char alphanumeric strings
// that are NOT the placeholder).
const hasRealKey = /sk-[A-Za-z0-9_-]{16,}/.test(currentCode);
const handleCopy = useCallback(async () => {
if (hasRealKey) return; // Never copy if somehow a real key slipped through
try {
await navigator.clipboard.writeText(currentCode);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Clipboard API unavailable (e.g. insecure context) — fail silently
}
}, [currentCode, hasRealKey]);
// Close on Escape
useEffect(() => {
function onKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") {
onClose();
}
}
document.addEventListener("keydown", onKeyDown);
return () => document.removeEventListener("keydown", onKeyDown);
}, [onClose]);
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
onClick={onClose}
role="dialog"
aria-modal="true"
aria-label="Export code"
>
<div
className="bg-surface border border-border rounded-xl w-[640px] max-w-[96vw] max-h-[80vh] flex flex-col shadow-2xl"
onClick={(e) => e.stopPropagation()}
>
{/* Modal header */}
<div className="flex items-center justify-between px-5 py-3.5 border-b border-border shrink-0">
<div className="flex items-center gap-2">
<span className="font-mono text-sm text-text-muted">&lt;/&gt;</span>
<h2 className="text-sm font-semibold text-text-main">Export code</h2>
</div>
<button
onClick={onClose}
className="p-1 rounded text-text-muted hover:text-text-main hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
aria-label="Close export modal"
>
<span className="material-symbols-outlined text-[18px]">close</span>
</button>
</div>
{/* Language tabs */}
<div className="flex items-center gap-1 px-4 pt-3 shrink-0" role="tablist">
{LANGUAGE_TABS.map((lang) => (
<button
key={lang.id}
role="tab"
aria-selected={activeLanguage === lang.id}
onClick={() => {
setActiveLanguage(lang.id);
setCopied(false);
}}
className={`px-3 py-1.5 text-xs font-medium rounded transition-colors ${
activeLanguage === lang.id
? "bg-primary/10 text-primary"
: "text-text-muted hover:text-text-main hover:bg-black/5 dark:hover:bg-white/5"
}`}
>
{lang.label}
</button>
))}
</div>
{/* Code block */}
<div className="flex-1 overflow-y-auto px-4 pt-3 pb-4 min-h-0">
{hasRealKey ? (
<div className="text-xs text-destructive bg-destructive/10 rounded p-3">
Security warning: export blocked a real API key was detected in the output.
Please reset your API key and try again.
</div>
) : (
<pre className="text-xs font-mono text-text-main bg-bg-alt border border-border rounded-lg p-4 overflow-x-auto whitespace-pre-wrap break-all">
<code>{currentCode}</code>
</pre>
)}
{/* Placeholder hint */}
<p className="text-[11px] text-text-muted mt-2">
Replace{" "}
<code className="font-mono text-primary">{API_KEY_PLACEHOLDER}</code>
{" "}with your actual API key, or set it as an environment variable.
</p>
</div>
{/* Footer with copy button */}
<div className="flex items-center justify-end gap-3 px-5 py-3 border-t border-border shrink-0">
<button
onClick={onClose}
className="text-xs px-3 py-1.5 rounded border border-border text-text-muted hover:text-text-main hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
>
Close
</button>
<button
onClick={handleCopy}
disabled={hasRealKey}
className={`flex items-center gap-1.5 text-xs px-3 py-1.5 rounded border transition-colors ${
copied
? "border-green-500 text-green-500 bg-green-500/10"
: "border-primary text-primary hover:bg-primary/10"
} disabled:opacity-40 disabled:cursor-not-allowed`}
aria-label={`Copy ${activeLanguage} code`}
>
<span className="material-symbols-outlined text-[14px]">
{copied ? "check" : "content_copy"}
</span>
{copied ? "Copied!" : "Copy"}
</button>
</div>
</div>
</div>
);
}