diff --git a/index.html b/index.html index 5f246fa..a33049a 100644 --- a/index.html +++ b/index.html @@ -99,11 +99,11 @@
@@ -165,7 +165,7 @@ function showSuneMenu(btn,id){menuSuneId=id;const r=btn.getBoundingClientRect(); el.historyList.addEventListener('click',async e=>{const openBtn=e.target.closest('[data-open-thread]'),menuBtn=e.target.closest('[data-thread-menu]');if(openBtn){const id=openBtn.getAttribute('data-open-thread'),th=threads.find(t=>t.id===id);if(!th)return;state.currentThreadId=id;renderSuneHTML();clearChat();state.messages=Array.isArray(th.messages)?[...th.messages]:[];for(const m of state.messages){const b=msgRow(m);b.dataset.mid=m.id||'';renderMarkdown(b,m.content)}queueMicrotask(()=>el.chat.scrollTo({top:el.chat.scrollHeight,behavior:'smooth'}));el.historyPanel.classList.add('translate-x-full');el.historyOverlay.classList.add('hidden');hideHistoryMenu();return}if(menuBtn){e.stopPropagation();showHistoryMenu(menuBtn,menuBtn.getAttribute('[data-thread-menu]')?menuBtn.getAttribute('[data-thread-menu]'):menuBtn.getAttribute('data-thread-menu'))}}) el.historyMenu.addEventListener('click',async e=>{const act=e.target.closest('[data-action]')?.getAttribute('data-action');if(!act||!menuThreadId)return;const th=threads.find(t=>t.id===menuThreadId);if(!th)return;if(act==='pin'){th.pinned=!th.pinned}else if(act==='rename'){const nv=prompt('Rename to:',th.title);if(nv!=null){th.title=titleFrom(nv);th.updatedAt=Date.now()}}else if(act==='delete'){if(confirm('Delete this chat?')){threads=threads.filter(x=>x.id!==th.id);if(state.currentThreadId===th.id){state.currentThreadId=null;clearChat()}}}else if(act==='count_tokens'){const msgs=Array.isArray(th.messages)?th.messages:[];let totalChars=0;for(const m of msgs){if(!m||!m.role||m.role==='system')continue;totalChars+=String(m.content||'').length}const tokens=Math.max(0,Math.ceil(totalChars/4));const k=tokens>=1000?Math.round(tokens/1000)+'k':String(tokens);alert(tokens+' tokens ('+k+')')}hideHistoryMenu();await tsave(threads);renderHistory()}) el.suneList.addEventListener('click',e=>{const menuBtn=e.target.closest('[data-sune-menu]');if(menuBtn){e.stopPropagation();showSuneMenu(menuBtn,menuBtn.getAttribute('[data-sune-menu]')?menuBtn.getAttribute('[data-sune-menu]'):menuBtn.getAttribute('data-sune-menu'));return}const btn=e.target.closest('[data-sune-id]');if(!btn)return;const id=btn.getAttribute('data-sune-id');if(id){su.setActiveId(id);renderSidebar();reflectActiveSune();state.currentThreadId=null;clearChat();document.getElementById('sidebar').classList.add('-translate-x-full');document.getElementById('sidebarOverlay').classList.add('hidden')}}) -el.suneMenu.addEventListener('click',e=>{const act=e.target.closest('[data-action]')?.getAttribute('data-action');if(!act||!menuSuneId)return;const s=sunes.find(x=>x.id===menuSuneId);if(!s)return;if(act==='pin')s.pinned=!s.pinned;else if(act==='rename'){const nv=prompt('Rename sune to:',s.name);if(nv!=null)s.name=nv.trim()||s.name}else if(act==='pfp'){const url=prompt('Image URL:',s.avatar||'');if(url!==null)s.avatar=url.trim()}s.updatedAt=Date.now();su.save(sunes);hideSuneMenu();renderSidebar();reflectActiveSune()}) +el.suneMenu.addEventListener('click',e=>{const act=e.target.closest('[data-action]')?.getAttribute('data-action');if(!act||!menuSuneId)return;const s=sunes.find(x=>x.id===menuSuneId);if(!s)return;if(act==='pin')s.pinned=!s.pinned;else if(act==='rename'){const nv=prompt('Rename sune to:',s.name);if(nv!=null)s.name=nv.trim()}else if(act==='pfp'){const url=prompt('Image URL:',s.avatar||'');if(url!==null)s.avatar=url.trim()}s.updatedAt=Date.now();su.save(sunes);hideSuneMenu();renderSidebar();reflectActiveSune()}) function updateAttachBadge(){const n=state.attachments.length;el.attachBadge.textContent=String(n);el.attachBadge.classList.toggle('hidden',n===0)} async function toAttach(file){if(file instanceof File){const name=file.name||'file',mime=(file.type||'application/octet-stream').toLowerCase(),bytes=file.size||0; if(/^image\//.test(mime)||/\.(png|jpe?g|webp|gif)$/i.test(name)){const data=await asDataURL(file);return {name,bytes,mime,data,mode:'dataURL',part:{type:'image_url',image_url:{url:data}}} } if(mime==='application/pdf'||/\.pdf$/i.test(file.name||'')){const data=await asDataURL(file);return {name:file.name||'file.pdf',bytes:file.size||0,mime:'application/pdf',data:b64(data),mode:'base64',part:{type:'file',file:{filename:file.name||'file.pdf',file_data:b64(data)}}} @@ -187,7 +187,7 @@ function openSettings(){const a=getActiveSune(),s=a.settings;el.set_model.value= const closeSettings=()=>{el.settingsModal.classList.add('hidden')} const tabs={Model:['tabModel','panelModel'],Prompt:['tabPrompt','panelPrompt'],Script:['tabScript','panelScript']} function showScriptSubTab(key){['HTML','JS'].forEach(k=>{const on=k===key;el['subTab'+k].classList.toggle('bg-black',on);el['subTab'+k].classList.toggle('text-white',on);el['subTab'+k].classList.toggle('bg-gray-100',!on);el['panel'+(k==='HTML'?'HTML':'JS')].classList.toggle('hidden',!on)})} -function showTab(key){Object.entries(tabs).forEach(([k,[tb,pn]])=>{el[tb].classList.toggle('border-black',k===key);el[pn].classList.toggle('hidden',k!==key)});if(key==='Script'){ensureJars().then(({js,html})=>{const s=getActiveSune().settings;js.updateCode(s.script||'');html.updateCode(s.html||'')});showScriptSubTab('JS')}} +function showTab(key){Object.entries(tabs).forEach(([k,[tb,pn]])=>{el[tb].classList.toggle('border-black',k===key);el[pn].classList.toggle('hidden',k!==key)});if(key==='Script'){ensureJars().then(({js,html})=>{const s=getActiveSune().settings;js.updateCode(s.script||'');html.updateCode(s.html||'')});showScriptSubTab('HTML')}} el.settingsBtnTop.addEventListener('click',openSettings) el.closeSettings.addEventListener('click',closeSettings) el.cancelSettings.addEventListener('click',closeSettings)