+
+ Generator
+
+
+ {GENERATOR_TABS.map(({ value, label }) => (
+
+ ))}
+
+
+
+ Options
+
+
+ {/* ── Password ── */}
+ {type === 'password' && (
+
+
setPwOpts((o) => ({ ...o, length: v }))}
+ />
+
+
+ Character sets
+
+
+ {([
+ { key: 'uppercase', label: 'A–Z', hint: 'Uppercase' },
+ { key: 'lowercase', label: 'a–z', hint: 'Lowercase' },
+ { key: 'numbers', label: '0–9', hint: 'Numbers' },
+ { key: 'symbols', label: '!@#', hint: 'Symbols' },
+ ] as const).map(({ key, label, hint }) => (
+
+ ))}
+
+
+ {strength && (
+
+
+
+ Strength
+
+
+ {entropy} bits
+
+
+
+
+ {strength.label}
+
+
+ )}
+
+ )}
+
+ {/* ── UUID ── */}
+ {type === 'uuid' && (
+
+
+
+ Generates a cryptographically random UUID v4 using the browser's built-in{' '}
+ crypto.randomUUID().
+
+
+
+ Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+
+
+ )}
+
+ {/* ── API Key ── */}
+ {type === 'apikey' && (
+
+
setApiOpts((o) => ({ ...o, length: v }))}
+ />
+
+
+ Encoding
+
+
+
+
+
+ Prefix (optional)
+
+ setApiOpts((o) => ({ ...o, prefix: e.target.value }))}
+ placeholder="sk, pk, api..."
+ className="w-full bg-transparent border border-border/40 rounded-lg px-2.5 py-1.5 text-xs font-mono outline-none focus:border-primary/50 transition-colors text-foreground/80 placeholder:text-muted-foreground/25"
+ />
+
+
+ )}
+
+ {/* ── Hash ── */}
+ {type === 'hash' && (
+
+
+
+ Algorithm
+
+
+
+
+
+ Input (empty = random)
+
+
+
+ )}
+
+ {/* ── Token ── */}
+ {type === 'token' && (
+
+
+
+ Byte length
+
+
+ {[16, 32, 48, 64].map((b) => (
+
+ ))}
+
+
+ {tokenOpts.bytes * 8} bits of entropy
+
+
+
+
+ Encoding
+
+
+
+
+ )}
+