mirror of
https://github.com/clucraft/PriceGhost.git
synced 2026-07-05 16:02:12 +02:00
Fix password visibility toggle UX
- Change confusing placeholder from bullets to "Saved - enter new value to replace" - Only show eye toggle when field has actual content to reveal - Add z-index and improved click handling for toggle button Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
81bbd8538f
commit
b885e4ef57
2 changed files with 21 additions and 13 deletions
|
|
@ -4,23 +4,30 @@ interface PasswordInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
|
||||||
// All standard input props are inherited
|
// All standard input props are inherited
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PasswordInput({ style, ...props }: PasswordInputProps) {
|
export default function PasswordInput({ style, value, ...props }: PasswordInputProps) {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
const hasValue = value !== undefined && value !== null && String(value).length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: 'relative', display: 'flex' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
<input
|
<input
|
||||||
{...props}
|
{...props}
|
||||||
|
value={value}
|
||||||
type={visible ? 'text' : 'password'}
|
type={visible ? 'text' : 'password'}
|
||||||
style={{
|
style={{
|
||||||
...style,
|
...style,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
paddingRight: '2.5rem',
|
paddingRight: hasValue ? '2.5rem' : '0.75rem',
|
||||||
|
boxSizing: 'border-box',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<button
|
{hasValue && <button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setVisible(!visible)}
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setVisible(!visible);
|
||||||
|
}}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: '0.5rem',
|
right: '0.5rem',
|
||||||
|
|
@ -33,7 +40,8 @@ export default function PasswordInput({ style, ...props }: PasswordInputProps) {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
color: 'var(--text-muted)',
|
color: visible ? 'var(--primary)' : 'var(--text-muted)',
|
||||||
|
zIndex: 10,
|
||||||
}}
|
}}
|
||||||
title={visible ? 'Hide' : 'Show'}
|
title={visible ? 'Hide' : 'Show'}
|
||||||
aria-label={visible ? 'Hide password' : 'Show password'}
|
aria-label={visible ? 'Hide password' : 'Show password'}
|
||||||
|
|
@ -71,7 +79,7 @@ export default function PasswordInput({ style, ...props }: PasswordInputProps) {
|
||||||
<circle cx="12" cy="12" r="3" />
|
<circle cx="12" cy="12" r="3" />
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -987,7 +987,7 @@ export default function Settings() {
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
value={telegramBotToken}
|
value={telegramBotToken}
|
||||||
onChange={(e) => setTelegramBotToken(e.target.value)}
|
onChange={(e) => setTelegramBotToken(e.target.value)}
|
||||||
placeholder={notificationSettings?.telegram_configured ? '••••••••••••••••' : 'Enter your bot token'}
|
placeholder={notificationSettings?.telegram_configured ? 'Saved - enter new value to replace' : 'Enter your bot token'}
|
||||||
/>
|
/>
|
||||||
<p className="hint">Create a bot via @BotFather on Telegram to get a token</p>
|
<p className="hint">Create a bot via @BotFather on Telegram to get a token</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1056,7 +1056,7 @@ export default function Settings() {
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
value={discordWebhookUrl}
|
value={discordWebhookUrl}
|
||||||
onChange={(e) => setDiscordWebhookUrl(e.target.value)}
|
onChange={(e) => setDiscordWebhookUrl(e.target.value)}
|
||||||
placeholder={notificationSettings?.discord_configured ? '••••••••••••••••' : 'https://discord.com/api/webhooks/...'}
|
placeholder={notificationSettings?.discord_configured ? 'Saved - enter new value to replace' : 'https://discord.com/api/webhooks/...'}
|
||||||
/>
|
/>
|
||||||
<p className="hint">Server Settings → Integrations → Webhooks → New Webhook</p>
|
<p className="hint">Server Settings → Integrations → Webhooks → New Webhook</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1114,7 +1114,7 @@ export default function Settings() {
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
value={pushoverUserKey}
|
value={pushoverUserKey}
|
||||||
onChange={(e) => setPushoverUserKey(e.target.value)}
|
onChange={(e) => setPushoverUserKey(e.target.value)}
|
||||||
placeholder={notificationSettings?.pushover_configured ? '••••••••••••••••' : 'Enter your user key'}
|
placeholder={notificationSettings?.pushover_configured ? 'Saved - enter new value to replace' : 'Enter your user key'}
|
||||||
/>
|
/>
|
||||||
<p className="hint">Find your User Key on the Pushover dashboard after logging in</p>
|
<p className="hint">Find your User Key on the Pushover dashboard after logging in</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1124,7 +1124,7 @@ export default function Settings() {
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
value={pushoverAppToken}
|
value={pushoverAppToken}
|
||||||
onChange={(e) => setPushoverAppToken(e.target.value)}
|
onChange={(e) => setPushoverAppToken(e.target.value)}
|
||||||
placeholder={notificationSettings?.pushover_configured ? '••••••••••••••••' : 'Enter your app token'}
|
placeholder={notificationSettings?.pushover_configured ? 'Saved - enter new value to replace' : 'Enter your app token'}
|
||||||
/>
|
/>
|
||||||
<p className="hint">Create an application at pushover.net/apps to get an API token</p>
|
<p className="hint">Create an application at pushover.net/apps to get an API token</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1208,7 +1208,7 @@ export default function Settings() {
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
value={anthropicApiKey}
|
value={anthropicApiKey}
|
||||||
onChange={(e) => setAnthropicApiKey(e.target.value)}
|
onChange={(e) => setAnthropicApiKey(e.target.value)}
|
||||||
placeholder={aiSettings?.anthropic_configured ? '••••••••••••••••' : 'sk-ant-...'}
|
placeholder={aiSettings?.anthropic_configured ? 'Saved - enter new value to replace' : 'sk-ant-...'}
|
||||||
/>
|
/>
|
||||||
<p className="hint">
|
<p className="hint">
|
||||||
Get your API key from{' '}
|
Get your API key from{' '}
|
||||||
|
|
@ -1226,7 +1226,7 @@ export default function Settings() {
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
value={openaiApiKey}
|
value={openaiApiKey}
|
||||||
onChange={(e) => setOpenaiApiKey(e.target.value)}
|
onChange={(e) => setOpenaiApiKey(e.target.value)}
|
||||||
placeholder={aiSettings?.openai_configured ? '••••••••••••••••' : 'sk-...'}
|
placeholder={aiSettings?.openai_configured ? 'Saved - enter new value to replace' : 'sk-...'}
|
||||||
/>
|
/>
|
||||||
<p className="hint">
|
<p className="hint">
|
||||||
Get your API key from{' '}
|
Get your API key from{' '}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue