()
| 212 | } |
| 213 | |
| 214 | function APIKeyTab() { |
| 215 | const { apiKey, setApiKey } = useStore() |
| 216 | const [showKey, setShowKey] = useState(false) |
| 217 | const [localKey, setLocalKey] = useState(apiKey) |
| 218 | const [saved, setSaved] = useState(false) |
| 219 | |
| 220 | const handleBlur = () => { |
| 221 | if (localKey !== apiKey) { |
| 222 | setApiKey(localKey) |
| 223 | setSaved(true) |
| 224 | setTimeout(() => setSaved(false), 2000) |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | return ( |
| 229 | <div className="space-y-4"> |
| 230 | <div> |
| 231 | <h3 className="text-lg font-semibold mb-2">OpenRouter API Key</h3> |
| 232 | <p className="text-sm theme-secondary mb-4"> |
| 233 | Your API key is stored locally and never sent to G0DM0D3 servers. |
| 234 | Get your key at{' '} |
| 235 | <a |
| 236 | href="https://openrouter.ai/keys" |
| 237 | target="_blank" |
| 238 | rel="noopener noreferrer" |
| 239 | className="theme-primary underline" |
| 240 | > |
| 241 | openrouter.ai |
| 242 | </a> |
| 243 | </p> |
| 244 | </div> |
| 245 | |
| 246 | <div className="relative"> |
| 247 | <input |
| 248 | type={showKey ? 'text' : 'password'} |
| 249 | value={localKey} |
| 250 | onChange={(e) => setLocalKey(e.target.value)} |
| 251 | onBlur={handleBlur} |
| 252 | placeholder="sk-or-v1-..." |
| 253 | className="w-full px-4 py-3 pr-20 bg-theme-dim border border-theme-primary rounded-lg |
| 254 | focus:outline-none focus:glow-box" |
| 255 | /> |
| 256 | <div className="absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2"> |
| 257 | {saved && ( |
| 258 | <span className="flex items-center gap-1 text-xs text-green-500"> |
| 259 | <Check className="w-3 h-3" /> |
| 260 | Saved |
| 261 | </span> |
| 262 | )} |
| 263 | <button |
| 264 | onClick={() => setShowKey(!showKey)} |
| 265 | className="p-1 hover:theme-primary transition-colors" |
| 266 | aria-label={showKey ? 'Hide key' : 'Show key'} |
| 267 | > |
| 268 | {showKey ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />} |
| 269 | </button> |
| 270 | </div> |
| 271 | </div> |
nothing calls this directly
no outgoing calls
no test coverage detected