diff --git a/src/main.js b/src/main.js index 75fe75c..8844899 100644 --- a/src/main.js +++ b/src/main.js @@ -31,6 +31,7 @@ const suneRow=a=>`
Copy').on('click',async e=>{e.stopPropagation();try{await navigator.clipboard.writeText(code.innerText);$btn.text('Copied');setTimeout(()=>$btn.text('Copy'),1200)}catch{}});const $container=$('
');$container.append($(`${countText} chars`),$btn);$pre.append($container)}if(doHL&&window.hljs&&code.textContent.length<100000)hljs.highlightElement(code)})} const md=window.markdownit({html:false,linkify:true,typographer:true,breaks:true}).use(window.texmath,{engine:window.katex,delimiters:'dollars',katexOptions:{macros:{"\\RR":"\\mathbb{R}"}}}) +const getSuneLabel=m=>{const name=(m&&m.sune_name)||SUNE.name,modelShort=getModelShort(m&&m.model);return `${name} · ${modelShort}`} function _createMessageRow(m){const role=typeof m==='string'?m:(m&&m.role)||'assistant',meta=typeof m==='string'?{}:m||{},isUser=role==='user',$row=$('
'),$head=$('
'),$avatar=$('
');const uAva=isUser?USER.avatar:meta.avatar;uAva?$avatar.attr('class','msg-avatar shrink-0 h-7 w-7 rounded-full overflow-hidden').html(``):$avatar.attr('class',`${isUser?'bg-gray-900 text-white':'bg-gray-200 text-gray-900'} msg-avatar shrink-0 h-7 w-7 rounded-full flex items-center justify-center`).text(isUser?'👤':'✺');const $name=$('
').text(isUser?USER.name:getSuneLabel(meta));const $deleteBtn=$('').on('click',async e=>{e.stopPropagation();state.messages=state.messages.filter(msg=>msg.id!==m.id);$row.remove();await THREAD.persist()});const $copyBtn=$('').on('click',async function(e){e.stopPropagation();try{await navigator.clipboard.writeText(partsToText(m));$(this).html('');icons();setTimeout(()=>{$(this).html('');icons()},1200)}catch{}});$head.append($avatar,$name,$copyBtn,$deleteBtn);const $bubble=$(`
`);$row.append($head,$bubble);return $row} function msgRow(m){const $row=_createMessageRow(m);$(el.messages).append($row);queueMicrotask(()=>{el.chat.scrollTo({top:el.chat.scrollHeight,behavior:'smooth'});icons()});return $row.find('.msg-bubble')[0]} const renderMarkdown=window.renderMarkdown=function(node,text,opt={enhance:true,highlight:true}){node.innerHTML=md.render(text);if(opt.enhance)enhanceCodeBlocks(node,opt.highlight)} @@ -131,7 +132,7 @@ function closeAccountSettings(){el.accountSettingsModal.classList.add('hidden')} $(el.accountSettingsOption).on('click',()=>{el.userMenu.classList.add('hidden');openAccountSettings()}) $(el.closeAccountSettings).on('click',closeAccountSettings) $(el.cancelAccountSettings).on('click',closeAccountSettings) -$(el.accountSettingsModal).on('click',e=>{if(e.target===el.accountSettingsModal||e.target.classList.contains('bg-black/30'))closeAccountSettings()}) +$(el.accountSettingsModal).on('click',e=>{if(e.target===el.accountSettingsModal||e.target.classList.contains('bg-black/30'))closeSettings()}) $(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.apiKeyClaude=String(el.set_api_key_claude.value||'').trim();USER.apiKeyCloudflare=String(el.set_api_key_cf.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();USER.donor=el.set_donor.checked;closeAccountSettings()}) el.gcpSAUploadBtn.onclick=()=>el.gcpSAInput.click();el.gcpSAInput.onchange=async e=>{const f=e.target.files?.[0];if(!f)return;try{const t=await f.text(),d=JSON.parse(t);if(!d.project_id)throw new Error('Invalid');USER.gcpSA=d;el.gcpSAUploadBtn.textContent=`Uploaded: ${d.project_id}`;alert('GCP SA loaded.')}catch{alert('Failed to load GCP SA.')}};$(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 p=i.type==='password';i.type=p?'text':'password';b.querySelector('i').setAttribute('data-lucide',p?'eye-off':'eye');lucide.createIcons()}); el.accountTabGeneral.onclick=()=>showAccountTab('General');el.accountTabAPI.onclick=()=>showAccountTab('API');el.accountTabUser.onclick=()=>showAccountTab('User') @@ -151,4 +152,3 @@ const getActiveHtmlParts=()=>!el.htmlEditor.classList.contains('hidden')?[el.htm $(el.copyHTML).on('click',async()=>{try{await navigator.clipboard.writeText(getActiveHtmlParts()[0].textContent||'')}catch{}}) $(el.pasteHTML).on('click',async()=>{try{const t=await navigator.clipboard.readText();const[editor,jar]=getActiveHtmlParts();if(jar&&jar.updateCode)jar.updateCode(t);else if(editor)editor.textContent=t}catch{}}) Object.assign(window,{icons,haptic,clamp,num,int,gid,esc,positionPopover,sid,fmtSize,asDataURL,b64,makeSune,getModelShort,resolveSuneSrc,processSuneIncludes,renderSuneHTML,reflectActiveSune,suneRow,enhanceCodeBlocks,getSuneLabel,_createMessageRow,msgRow,partsToText,addSuneBubbleStreaming,clearChat,payloadWithSampling,setBtnStop,setBtnSend,localDemoReply,titleFrom,serializeThreadName,deserializeThreadName,ensureThreadOnFirstUser,generateTitleWithAI,threadRow,renderThreads,hideThreadPopover,showThreadPopover,hideSunePopover,showSunePopover,updateAttachBadge,toAttach,ensureJars,openSettings,closeSettings,showTab,dl,ts,kbUpdate,kbBind,activeMeta,init,showHtmlTab,showAccountTab,openAccountSettings,closeAccountSettings,getBubbleById,syncActiveThread,syncWhileBusy,onForeground,getActiveHtmlParts,imgToWebp,cacheStore,ghApi,parseGhUrl,pullThreads}); -