mirror of
https://github.com/sune-org/sune.git
synced 2026-10-29 04:54:51 +00:00
Restore password key fields and add a copy button per key
Masking with -webkit-text-security didn't help: Chrome on Android flags those fields as custom passwords and still hides Copy. Key fields are back to type=password with the type toggle, and each key label now has an inline copy icon that copies the value straight from the field, masked or not. The eye icon fix stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+2
-1
@@ -375,7 +375,8 @@ $(el.accountSettingsModal).on('click',e=>{if(e.target===el.accountSettingsModal|
|
|||||||
$(el.setUserAvatarBtn).on('click',()=>el.userAvatarInput.click());
|
$(el.setUserAvatarBtn).on('click',()=>el.userAvatarInput.click());
|
||||||
$(el.userAvatarInput).on('change',async()=>{const f=el.userAvatarInput.files?.[0];if(!f)return;try{const v=await imgToWebp(f);USER.avatar=v;el.userAvatarPreview.src=v;el.userAvatarPreview.classList.remove('bg-gray-200');renderUserUI()}catch{}});
|
$(el.userAvatarInput).on('change',async()=>{const f=el.userAvatarInput.files?.[0];if(!f)return;try{const v=await imgToWebp(f);USER.avatar=v;el.userAvatarPreview.src=v;el.userAvatarPreview.classList.remove('bg-gray-200');renderUserUI()}catch{}});
|
||||||
$(el.accountSettingsForm).on('submit',e=>{e.preventDefault();USER.provider=el.set_provider.value||'openrouter';USER.apiKeyOpenRouter=String(el.set_api_key_or.value||'').trim();USER.apiKeyOpenAI=String(el.set_api_key_oai.value||'').trim();USER.apiKeyGoogle=String(el.set_api_key_g.value||'').trim();USER.apiKeyAnthropic=String(el.set_api_key_ant.value||'').trim();USER.apiKeyCloudflare=String(el.set_api_key_cf.value||'').trim();USER.customKey1=String(el.set_api_key_custom1.value||'').trim();USER.masterPrompt=String(el.set_master_prompt.value||'').trim();USER.titleModel=String(el.set_title_model.value||'').trim();USER.githubToken=String(el.set_gh_token.value||'').trim();USER.name=String(el.set_user_name.value||'').trim();renderUserUI();closeAccountSettings()})
|
$(el.accountSettingsForm).on('submit',e=>{e.preventDefault();USER.provider=el.set_provider.value||'openrouter';USER.apiKeyOpenRouter=String(el.set_api_key_or.value||'').trim();USER.apiKeyOpenAI=String(el.set_api_key_oai.value||'').trim();USER.apiKeyGoogle=String(el.set_api_key_g.value||'').trim();USER.apiKeyAnthropic=String(el.set_api_key_ant.value||'').trim();USER.apiKeyCloudflare=String(el.set_api_key_cf.value||'').trim();USER.customKey1=String(el.set_api_key_custom1.value||'').trim();USER.masterPrompt=String(el.set_master_prompt.value||'').trim();USER.titleModel=String(el.set_title_model.value||'').trim();USER.githubToken=String(el.set_gh_token.value||'').trim();USER.name=String(el.set_user_name.value||'').trim();renderUserUI();closeAccountSettings()})
|
||||||
$(el.accountPanelAPI).on('click',e=>{const b=e.target.closest('[data-reveal-for]');if(!b)return;const i=document.getElementById(b.dataset.revealFor);if(!i)return;const m=i.classList.toggle('key-mask');b.innerHTML=`<i data-lucide="${m?'eye':'eye-off'}" class="h-4 w-4"></i>`;icons()});
|
const setIco=(b,n)=>{b.innerHTML=`<i data-lucide="${n}" class="h-4 w-4"></i>`;icons()};
|
||||||
|
$(el.accountPanelAPI).on('click',async e=>{const c=e.target.closest('[data-copy-for]');if(c){if(await copyToClipboard(document.getElementById(c.dataset.copyFor)?.value||''))setIco(c,'check'),setTimeout(()=>setIco(c,'copy'),1200);return}const b=e.target.closest('[data-reveal-for]'),i=b&&document.getElementById(b.dataset.revealFor);if(!i)return;const p=i.type==='password';i.type=p?'text':'password';setIco(b,p?'eye-off':'eye')});
|
||||||
el.accountTabGeneral.onclick=()=>showAccountTab('General');el.accountTabAPI.onclick=()=>showAccountTab('API');el.accountTabUser.onclick=()=>showAccountTab('User')
|
el.accountTabGeneral.onclick=()=>showAccountTab('General');el.accountTabAPI.onclick=()=>showAccountTab('API');el.accountTabUser.onclick=()=>showAccountTab('User')
|
||||||
el.exportAccountSettings.onclick=()=>dl(`sune-account-${ts()}.json`,{v:1,provider:USER.provider,apiKeyOpenRouter:USER.apiKeyOpenRouter,apiKeyOpenAI:USER.apiKeyOpenAI,apiKeyGoogle:USER.apiKeyGoogle,apiKeyAnthropic:USER.apiKeyAnthropic,apiKeyCloudflare:USER.apiKeyCloudflare,customKey1:USER.customKey1,masterPrompt:USER.masterPrompt,titleModel:USER.titleModel,githubToken:USER.githubToken,userName:USER.name,userAvatar:USER.avatar});
|
el.exportAccountSettings.onclick=()=>dl(`sune-account-${ts()}.json`,{v:1,provider:USER.provider,apiKeyOpenRouter:USER.apiKeyOpenRouter,apiKeyOpenAI:USER.apiKeyOpenAI,apiKeyGoogle:USER.apiKeyGoogle,apiKeyAnthropic:USER.apiKeyAnthropic,apiKeyCloudflare:USER.apiKeyCloudflare,customKey1:USER.customKey1,masterPrompt:USER.masterPrompt,titleModel:USER.titleModel,githubToken:USER.githubToken,userName:USER.name,userAvatar:USER.avatar});
|
||||||
el.importAccountSettings.onclick=()=>{el.importAccountSettingsInput.value='';el.importAccountSettingsInput.click()};
|
el.importAccountSettings.onclick=()=>{el.importAccountSettingsInput.value='';el.importAccountSettingsInput.click()};
|
||||||
|
|||||||
@@ -122,7 +122,7 @@
|
|||||||
<div><label class="block text-gray-700 font-medium mb-1">Master Prompt</label><textarea id="set_master_prompt" rows="6" class="w-full rounded-xl border border-gray-300 px-3 py-2" placeholder="Applies to all sunes on this device"></textarea><p class="mt-1 text-xs text-gray-500">Stored locally.</p></div>
|
<div><label class="block text-gray-700 font-medium mb-1">Master Prompt</label><textarea id="set_master_prompt" rows="6" class="w-full rounded-xl border border-gray-300 px-3 py-2" placeholder="Applies to all sunes on this device"></textarea><p class="mt-1 text-xs text-gray-500">Stored locally.</p></div>
|
||||||
<div><label class="block text-gray-700 font-medium mb-1">Model preference for titles</label><input id="set_title_model" type="text" class="w-full rounded-xl border border-gray-300 px-3 py-2" placeholder="or:google/gemma-3-12b-it"/><p class="mt-1 text-xs text-gray-500">Used for auto-generating thread titles.</p></div>
|
<div><label class="block text-gray-700 font-medium mb-1">Model preference for titles</label><input id="set_title_model" type="text" class="w-full rounded-xl border border-gray-300 px-3 py-2" placeholder="or:google/gemma-3-12b-it"/><p class="mt-1 text-xs text-gray-500">Used for auto-generating thread titles.</p></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="accountPanelAPI" class="p-4 overflow-y-auto hidden"><div class="grid grid-cols-2 gap-x-4 gap-y-4"><div><label class="block text-gray-700 font-medium mb-1">OpenRouter Key</label><div class="relative"><input id="set_api_key_or" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="key-mask w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="sk-or-..."><button type="button" data-reveal-for="set_api_key_or" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.apiKeyOpenRouter</code></p></div><div><label class="block text-gray-700 font-medium mb-1">OpenAI Key</label><div class="relative"><input id="set_api_key_oai" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="key-mask w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="sk-..."><button type="button" data-reveal-for="set_api_key_oai" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.apiKeyOpenAI</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Google Key</label><div class="relative"><input id="set_api_key_g" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="key-mask w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="AIza..."><button type="button" data-reveal-for="set_api_key_g" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Gemini/Studio. Use: <code>USER.apiKeyGoogle</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Anthropic Key</label><div class="relative"><input id="set_api_key_ant" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="key-mask w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="sk-ant-..."><button type="button" data-reveal-for="set_api_key_ant" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.apiKeyAnthropic</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Cloudflare Token</label><div class="relative"><input id="set_api_key_cf" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="key-mask w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="..."><button type="button" data-reveal-for="set_api_key_cf" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Not used. Use: <code>USER.apiKeyCloudflare</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Custom Key 1</label><div class="relative"><input id="set_api_key_custom1" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="key-mask w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="..."><button type="button" data-reveal-for="set_api_key_custom1" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.customKey1</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Github Token</label><div class="relative"><input id="set_gh_token" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="key-mask w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="ghp_..."><button type="button" data-reveal-for="set_gh_token" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.githubToken</code></p></div></div></div>
|
<div id="accountPanelAPI" class="p-4 overflow-y-auto hidden"><div class="grid grid-cols-2 gap-x-4 gap-y-4"><div><label class="block text-gray-700 font-medium mb-1">OpenRouter Key <button type="button" data-copy-for="set_api_key_or" class="inline-flex align-middle text-gray-400 hover:text-gray-600"><i data-lucide="copy" class="h-4 w-4"></i></button></label><div class="relative"><input id="set_api_key_or" type="password" class="w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="sk-or-..."><button type="button" data-reveal-for="set_api_key_or" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.apiKeyOpenRouter</code></p></div><div><label class="block text-gray-700 font-medium mb-1">OpenAI Key <button type="button" data-copy-for="set_api_key_oai" class="inline-flex align-middle text-gray-400 hover:text-gray-600"><i data-lucide="copy" class="h-4 w-4"></i></button></label><div class="relative"><input id="set_api_key_oai" type="password" class="w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="sk-..."><button type="button" data-reveal-for="set_api_key_oai" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.apiKeyOpenAI</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Google Key <button type="button" data-copy-for="set_api_key_g" class="inline-flex align-middle text-gray-400 hover:text-gray-600"><i data-lucide="copy" class="h-4 w-4"></i></button></label><div class="relative"><input id="set_api_key_g" type="password" class="w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="AIza..."><button type="button" data-reveal-for="set_api_key_g" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Gemini/Studio. Use: <code>USER.apiKeyGoogle</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Anthropic Key <button type="button" data-copy-for="set_api_key_ant" class="inline-flex align-middle text-gray-400 hover:text-gray-600"><i data-lucide="copy" class="h-4 w-4"></i></button></label><div class="relative"><input id="set_api_key_ant" type="password" class="w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="sk-ant-..."><button type="button" data-reveal-for="set_api_key_ant" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.apiKeyAnthropic</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Cloudflare Token <button type="button" data-copy-for="set_api_key_cf" class="inline-flex align-middle text-gray-400 hover:text-gray-600"><i data-lucide="copy" class="h-4 w-4"></i></button></label><div class="relative"><input id="set_api_key_cf" type="password" class="w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="..."><button type="button" data-reveal-for="set_api_key_cf" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Not used. Use: <code>USER.apiKeyCloudflare</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Custom Key 1 <button type="button" data-copy-for="set_api_key_custom1" class="inline-flex align-middle text-gray-400 hover:text-gray-600"><i data-lucide="copy" class="h-4 w-4"></i></button></label><div class="relative"><input id="set_api_key_custom1" type="password" class="w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="..."><button type="button" data-reveal-for="set_api_key_custom1" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.customKey1</code></p></div><div><label class="block text-gray-700 font-medium mb-1">Github Token <button type="button" data-copy-for="set_gh_token" class="inline-flex align-middle text-gray-400 hover:text-gray-600"><i data-lucide="copy" class="h-4 w-4"></i></button></label><div class="relative"><input id="set_gh_token" type="password" class="w-full rounded-xl border border-gray-300 px-3 py-2 pr-10" placeholder="ghp_..."><button type="button" data-reveal-for="set_gh_token" class="absolute inset-y-0 right-0 px-3 flex items-center text-gray-400 hover:text-gray-600"><i data-lucide="eye" class="h-4 w-4"></i></button></div><p class="mt-1 text-xs text-gray-500">Use: <code>USER.githubToken</code></p></div></div></div>
|
||||||
<div id="accountPanelUser" class="p-4 space-y-4 overflow-y-auto hidden">
|
<div id="accountPanelUser" class="p-4 space-y-4 overflow-y-auto hidden">
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<div class="relative"><img id="userAvatarPreview" class="h-16 w-16 rounded-full object-cover bg-gray-200"><button type="button" id="setUserAvatarBtn" class="absolute bottom-0 right-0 h-6 w-6 rounded-full bg-white border border-gray-300 flex items-center justify-center hover:bg-gray-100" aria-label="Edit photo"><i data-lucide="edit-3" class="h-3 w-3"></i></button></div>
|
<div class="relative"><img id="userAvatarPreview" class="h-16 w-16 rounded-full object-cover bg-gray-200"><button type="button" id="setUserAvatarBtn" class="absolute bottom-0 right-0 h-6 w-6 rounded-full bg-white border border-gray-300 flex items-center justify-center hover:bg-gray-100" aria-label="Edit photo"><i data-lucide="edit-3" class="h-3 w-3"></i></button></div>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ html,body{overscroll-behavior-y:contain;font-family:'Assistant',sans-serif}
|
|||||||
.msg-avatar{font-size:16px}
|
.msg-avatar{font-size:16px}
|
||||||
.menu-card{position:fixed;z-index:60;min-width:12rem;border-radius:0.75rem;border:1px solid #e5e7eb;background:#fff;box-shadow:0 10px 20px rgba(0,0,0,.08)}
|
.menu-card{position:fixed;z-index:60;min-width:12rem;border-radius:0.75rem;border:1px solid #e5e7eb;background:#fff;box-shadow:0 10px 20px rgba(0,0,0,.08)}
|
||||||
.menu-item{width:100%;text-align:left;padding:.5rem .75rem;font-size:0.875rem;display:flex;align-items:center;gap:.5rem}
|
.menu-item{width:100%;text-align:left;padding:.5rem .75rem;font-size:0.875rem;display:flex;align-items:center;gap:.5rem}
|
||||||
.key-mask{-webkit-text-security:disc}
|
|
||||||
#attachBtn{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
|
#attachBtn{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
|
||||||
#htmlEditor,#extensionHtmlEditor,#jsonSchemaEditor{outline:none;white-space:pre!important;font-size:11px;line-height:1.5;}
|
#htmlEditor,#extensionHtmlEditor,#jsonSchemaEditor{outline:none;white-space:pre!important;font-size:11px;line-height:1.5;}
|
||||||
:not(pre)>code{font-size:85%;padding:.2em .4em;margin:0;border-radius:6px;background-color:rgba(175,184,193,0.2)}
|
:not(pre)>code{font-size:85%;padding:.2em .4em;margin:0;border-radius:6px;background-color:rgba(175,184,193,0.2)}
|
||||||
|
|||||||
Reference in New Issue
Block a user