iamfebin's picture
feat: implement sandbox mode
a95fdd1
Raw
History Blame Contribute Delete
4.45 kB
import { useState, useEffect } from 'react';
import { Key, Eye, EyeOff, Save, Trash } from 'lucide-react';
export default function Settings() {
const [apiKey, setApiKey] = useState('');
const [showKey, setShowKey] = useState(false);
const [status, setStatus] = useState<string | null>(null);
useEffect(() => {
const savedKey = localStorage.getItem('sandbox_gemini_api_key') || '';
setApiKey(savedKey);
}, []);
const handleSave = () => {
if (apiKey.trim()) {
localStorage.setItem('sandbox_gemini_api_key', apiKey.trim());
setStatus('API Key saved successfully!');
} else {
localStorage.removeItem('sandbox_gemini_api_key');
setStatus('API Key cleared.');
}
setTimeout(() => setStatus(null), 3000);
};
const handleClear = () => {
localStorage.removeItem('sandbox_gemini_api_key');
setApiKey('');
setStatus('API Key cleared.');
setTimeout(() => setStatus(null), 3000);
};
return (
<div className="w-full h-full bg-[#fdf8e1] p-6 flex flex-col gap-5 select-none font-sans text-ink-black overflow-y-auto custom-scrollbar">
<div className="flex flex-col gap-2">
<h3 className="font-headline-md font-bold text-sm m-0 flex items-center gap-2">
<span className="material-symbols-outlined text-lg text-[#0ea5e9]">key</span>
CUSTOM GEMINI API CONFIG
</h3>
<p className="text-[9px] text-trash-gray font-bold leading-normal m-0 uppercase font-arcade">
Configure a custom Gemini API key for Sandbox Mode AI evaluations & explanations.
</p>
</div>
<div className="bg-white border-[3px] border-ink-black p-4 shadow-[4px_4px_0px_0px_rgba(30,41,59,1)] flex flex-col gap-4">
<div>
<label className="block text-xs font-bold text-ink-black uppercase tracking-wider mb-2 font-headline-md">
Gemini API Key
</label>
<div className="relative">
<Key className="absolute left-3.5 top-1/2 -translate-y-1/2 w-4 h-4 text-ink-black" />
<input
type={showKey ? 'text' : 'password'}
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
placeholder="AIzaSy..."
className="w-full bg-white border-[3px] border-ink-black rounded-lg py-2.5 pl-10 pr-10 text-ink-black placeholder-trash-gray focus:outline-none focus:bg-white text-xs font-code-mono shadow-[inset_2px_2px_0px_rgba(0,0,0,0.1)]"
/>
<button
type="button"
onClick={() => setShowKey(!showKey)}
className="absolute right-3.5 top-1/2 -translate-y-1/2 text-trash-gray hover:text-ink-black cursor-pointer bg-transparent border-0 outline-none"
>
{showKey ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
</button>
</div>
<span className="text-[9px] text-trash-gray mt-2 block font-medium leading-normal">
Your key is stored locally in your browser's localStorage and is only sent to the local server in request headers.
</span>
</div>
{status && (
<div className="p-3 border-[3px] border-ink-black bg-emerald-100 border-emerald-500 text-emerald-700 text-xs font-bold font-arcade leading-relaxed shadow-[2px_2px_0px_0px_rgba(30,41,59,1)]">
{status}
</div>
)}
<div className="flex flex-col sm:flex-row gap-3 pt-2 border-t border-slate-200">
<button
onClick={handleSave}
className="flex-1 flex items-center justify-center gap-2 py-2.5 border-[3px] border-ink-black bg-[#ffe24c] hover:bg-yellow-300 text-xs font-bold text-ink-black shadow-[3px_3px_0px_0px_#1E293B] active:translate-y-0.5 active:shadow-none transition-all cursor-pointer text-center uppercase"
>
<Save className="w-4 h-4" />
Save Key
</button>
<button
onClick={handleClear}
className="flex-1 flex items-center justify-center gap-2 py-2.5 border-[3px] border-ink-black bg-white hover:bg-slate-100 text-xs font-bold text-ink-black shadow-[3px_3px_0px_0px_#1E293B] active:translate-y-0.5 active:shadow-none transition-all cursor-pointer text-center uppercase"
>
<Trash className="w-4 h-4 text-rose-500" />
Clear Key
</button>
</div>
</div>
</div>
);
}