mirror of
https://github.com/multipleof4/sune.git
synced 2026-01-14 16:47:59 +00:00
Update index.html
This commit is contained in:
14
index.html
14
index.html
@@ -26,6 +26,7 @@
|
|||||||
<div class="justify-self-end"><button id="historyBtn" class="h-8 w-8 rounded-xl bg-gray-100 hover:bg-gray-200 active:scale-[.99] transition flex items-center justify-center" title="Threads" hx-on="click:renderHistory();document.getElementById('historyPanel').classList.remove('translate-x-full');document.getElementById('historyOverlay').classList.remove('hidden')"><i data-lucide="panel-right" class="h-5 w-5"></i></button></div>
|
<div class="justify-self-end"><button id="historyBtn" class="h-8 w-8 rounded-xl bg-gray-100 hover:bg-gray-200 active:scale-[.99] transition flex items-center justify-center" title="Threads" hx-on="click:renderHistory();document.getElementById('historyPanel').classList.remove('translate-x-full');document.getElementById('historyOverlay').classList.remove('hidden')"><i data-lucide="panel-right" class="h-5 w-5"></i></button></div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
<section id="suneHtml" class="px-4 py-3 border-b border-gray-200 hidden"></section>
|
||||||
<main id="chat" class="flex-1 overflow-y-auto no-scrollbar"><div id="messages" class="mx-auto w-full max-w-none px-0 py-4 sm:py-6 space-y-4" hx-on="click: if(event.target.closest('.msg-avatar')){document.getElementById('sidebar').classList.remove('-translate-x-full');document.getElementById('sidebarOverlay').classList.remove('hidden')}"></div><div class="h-24"></div></main>
|
<main id="chat" class="flex-1 overflow-y-auto no-scrollbar"><div id="messages" class="mx-auto w-full max-w-none px-0 py-4 sm:py-6 space-y-4" hx-on="click: if(event.target.closest('.msg-avatar')){document.getElementById('sidebar').classList.remove('-translate-x-full');document.getElementById('sidebarOverlay').classList.remove('hidden')}"></div><div class="h-24"></div></main>
|
||||||
<footer id="footer" class="sticky bottom-0 z-10 bg-gradient-to-t from-white via-white/95 to-white/40 pt-2 pb-[calc(12px+var(--safe-bottom))] border-t border-gray-200">
|
<footer id="footer" class="sticky bottom-0 z-10 bg-gradient-to-t from-white via-white/95 to-white/40 pt-2 pb-[calc(12px+var(--safe-bottom))] border-t border-gray-200">
|
||||||
<div class="mx-auto w-full max-w-none px-0">
|
<div class="mx-auto w-full max-w-none px-0">
|
||||||
@@ -94,15 +95,15 @@
|
|||||||
<div><label class="block text-gray-700 font-medium mb-1">Reasoning Effort</label><select id="set_reasoning_effort" class="w-full rounded-xl border border-gray-300 px-3 py-2"><option value="default">Default</option><option value="low">Low</option><option value="medium">Medium</option><option value="high">High</option></select><p class="mt-1 text-xs text-gray-500">Used only if supported by the model. (Default = Omitted)</p></div>
|
<div><label class="block text-gray-700 font-medium mb-1">Reasoning Effort</label><select id="set_reasoning_effort" class="w-full rounded-xl border border-gray-300 px-3 py-2"><option value="default">Default</option><option value="low">Low</option><option value="medium">Medium</option><option value="high">High</option></select><p class="mt-1 text-xs text-gray-500">Used only if supported by the model. (Default = Omitted)</p></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="panelPrompt" class="p-4 space-y-4 hidden">
|
<div id="panelPrompt" class="p-4 space-y-4 hidden">
|
||||||
<div><label class="block text-gray-700 font-medium mb-1">System Prompt</label><textarea id="set_system_prompt" rows="8" class="w-full rounded-xl border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-black/20" placeholder="Enter a system prompt to guide the sune"></textarea><p class="mt-1 text-xs text-gray-500">Saved per sune.</p></div>
|
<div><label class="block text-gray-700 font-medium mb-1">System Prompt</label><textarea id="set_system_prompt" rows="8" class="w-full rounded-xl border border-gray-300 px-3 py-2" placeholder="Enter a system prompt to guide the sune"></textarea><p class="mt-1 text-xs text-gray-500">Saved per sune.</p></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="panelScript" class="p-4 space-y-3 hidden">
|
<div id="panelScript" class="p-4 space-y-3 hidden">
|
||||||
<div class="grid grid-cols-2 gap-2 text-xs font-medium">
|
<div class="grid grid-cols-2 gap-2 text-xs font-medium">
|
||||||
<button type="button" id="subTabHTML" class="py-2 px-3 rounded-xl bg-gray-100 border border-gray-200">HTML</button>
|
<button type="button" id="subTabHTML" class="py-2 px-3 rounded-xl bg-gray-100 border border-gray-200">HTML</button>
|
||||||
<button type="button" id="subTabJS" class="py-2 px-3 rounded-xl bg-black text-white">JavaScript</button>
|
<button type="button" id="subTabJS" class="py-2 px-3 rounded-xl bg-black text-white">JavaScript</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="panelHTML" class=""><pre id="htmlEditor" class="w-full h-[50vh] p-3 rounded-xl border border-gray-300 bg-white overflow-auto font-mono text-[12px] leading-5" contenteditable="plaintext-only" spellcheck="false"></pre></div>
|
<div id="panelHTML" class=""><pre id="htmlEditor" class="w-full h-[50vh] p-3 rounded-xl border border-gray-300 bg-white overflow-auto font-mono text-[12px] leading-5" contenteditable="plaintext-only" spellcheck="false"></pre><p class="mt-1 text-xs text-gray-500">Scripts also run.</p></div>
|
||||||
<div id="panelJS" class=""><pre id="scriptEditor" class="w-full h=[50vh] h-[50vh] p-3 rounded-xl border border-gray-300 bg-white overflow-auto font-mono text-[12px] leading-5" contenteditable="plaintext-only" spellcheck="false"></pre><p class="mt-1 text-xs text-gray-500">Sunes can function call exported JS functions. (WIP)</p></div>
|
<div id="panelJS" class=""><pre id="scriptEditor" class="w-full h=[50vh] h-[50vh] p-3 rounded-xl border border-gray-300 bg-white overflow-auto font-mono text-[12px] leading-5" contenteditable="plaintext-only" spellcheck="false"></pre><p class="mt-1 text-xs text-gray-500">Put scripts in HTML instead for now. This does nothing.</p></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between gap-2 px-4 py-3 border-t">
|
<div class="flex items-center justify-between gap-2 px-4 py-3 border-t">
|
||||||
<button type="button" id="deleteSuneBtn" class="inline-flex items-center gap-2 px-3 py-2 rounded-xl border border-red-200 text-red-700 hover:bg-red-50"><svg viewBox="0 0 24 24" class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 6h18M8 6v12a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V6m-9 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg><span>Delete sune</span></button>
|
<button type="button" id="deleteSuneBtn" class="inline-flex items-center gap-2 px-3 py-2 rounded-xl border border-red-200 text-red-700 hover:bg-red-50"><svg viewBox="0 0 24 24" class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 6h18M8 6v12a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V6m-9 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg><span>Delete sune</span></button>
|
||||||
@@ -118,7 +119,7 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/localforage@1.10.0/dist/localforage.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/localforage@1.10.0/dist/localforage.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const DEFAULT_MODEL='openai/gpt-5-chat',DEFAULT_API_KEY=''
|
const DEFAULT_MODEL='openai/gpt-5-chat',DEFAULT_API_KEY=''
|
||||||
const el=Object.fromEntries(['chat','messages','composer','input','sendBtn','settingsBtnTop','settingsModal','settingsForm','closeSettings','cancelSettings','tabModel','tabPrompt','tabScript','panelModel','panelPrompt','panelScript','set_model','set_temperature','set_top_p','set_top_k','set_frequency_penalty','set_presence_penalty','set_repetition_penalty','set_min_p','set_top_a','set_reasoning_effort','set_system_prompt','deleteSuneBtn','sidebar','sidebarOverlay','sidebarBtn','suneList','newSuneBtn','userMenuBtn','userMenu','apiKeyOption','sunesImportOption','sunesExportOption','threadsImportOption','threadsExportOption','importInput','historyBtn','historyPanel','historyOverlay','historyList','closeHistory','historyMenu','suneMenu','footer','attachBtn','attachBadge','fileInput','scriptEditor','htmlEditor','subTabHTML','subTabJS','panelHTML','panelJS'].map(id=>[id,document.getElementById(id)]))
|
const el=Object.fromEntries(['chat','messages','composer','input','sendBtn','settingsBtnTop','settingsModal','settingsForm','closeSettings','cancelSettings','tabModel','tabPrompt','tabScript','panelModel','panelPrompt','panelScript','set_model','set_temperature','set_top_p','set_top_k','set_frequency_penalty','set_presence_penalty','set_repetition_penalty','set_min_p','set_top_a','set_reasoning_effort','set_system_prompt','deleteSuneBtn','sidebar','sidebarOverlay','sidebarBtn','suneList','newSuneBtn','userMenuBtn','userMenu','apiKeyOption','sunesImportOption','sunesExportOption','threadsImportOption','threadsExportOption','importInput','historyBtn','historyPanel','historyOverlay','historyList','closeHistory','historyMenu','suneMenu','footer','attachBtn','attachBadge','fileInput','scriptEditor','htmlEditor','subTabHTML','subTabJS','panelHTML','panelJS','suneHtml'].map(id=>[id,document.getElementById(id)]))
|
||||||
const icons=()=>window.lucide&&lucide.createIcons()
|
const icons=()=>window.lucide&&lucide.createIcons()
|
||||||
const clamp=(v,min,max)=>Math.max(min,Math.min(max,v)),num=(v,d)=>v==null||v===''||isNaN(+v)?d:+v,int=(v,d)=>v==null||v===''||isNaN(parseInt(v))?d:parseInt(v),gid=()=>Math.random().toString(36).slice(2,9),esc=s=>String(s).replace(/[&<>'"`]/g,c=>({"&":"&","<":"<",">":">","\"":""","'":"'","`":"`"}[c]))
|
const clamp=(v,min,max)=>Math.max(min,Math.min(max,v)),num=(v,d)=>v==null||v===''||isNaN(+v)?d:+v,int=(v,d)=>v==null||v===''||isNaN(parseInt(v))?d:parseInt(v),gid=()=>Math.random().toString(36).slice(2,9),esc=s=>String(s).replace(/[&<>'"`]/g,c=>({"&":"&","<":"<",">":">","\"":""","'":"'","`":"`"}[c]))
|
||||||
const fmtSize=b=>{const u=['B','KB','MB','GB','TB'];let i=0,x=b;while(x>=1024&&i<u.length-1){x/=1024;i++}return (x>=10?Math.round(x):Math.round(x*10)/10)+' '+u[i]}
|
const fmtSize=b=>{const u=['B','KB','MB','GB','TB'];let i=0,x=b;while(x>=1024&&i<u.length-1){x/=1024;i++}return (x>=10?Math.round(x):Math.round(x*10)/10)+' '+u[i]}
|
||||||
@@ -134,7 +135,8 @@ const getActiveSune=()=>sunes.find(a=>a.id===su.getActiveId())||sunes[0],createD
|
|||||||
const store=new Proxy({},{get(_,p){if(p==='apiKey')return globalStore.apiKey;const a=getActiveSune();if(p==='model')return a.settings.model;if(p in a.settings)return a.settings[p];if(p==='system_prompt')return a.settings.system_prompt},set(_,p,v){if(p==='apiKey'){globalStore.apiKey=v;return true}const i=sunes.findIndex(a=>a.id===getActiveSune().id);if(i>=0){if(p==='model')sunes[i].settings.model=v||DEFAULT_MODEL;else if(p==='system_prompt')sunes[i].settings.system_prompt=v||'';else sunes[i].settings[p]=v;sunes[i].updatedAt=Date.now();su.save(sunes);return true}return false}})
|
const store=new Proxy({},{get(_,p){if(p==='apiKey')return globalStore.apiKey;const a=getActiveSune();if(p==='model')return a.settings.model;if(p in a.settings)return a.settings[p];if(p==='system_prompt')return a.settings.system_prompt},set(_,p,v){if(p==='apiKey'){globalStore.apiKey=v;return true}const i=sunes.findIndex(a=>a.id===getActiveSune().id);if(i>=0){if(p==='model')sunes[i].settings.model=v||DEFAULT_MODEL;else if(p==='system_prompt')sunes[i].settings.system_prompt=v||'';else sunes[i].settings[p]=v;sunes[i].updatedAt=Date.now();su.save(sunes);return true}return false}})
|
||||||
const state={messages:[],busy:false,controller:null,currentThreadId:null,abortRequested:false,attachments:[]}
|
const state={messages:[],busy:false,controller:null,currentThreadId:null,abortRequested:false,attachments:[]}
|
||||||
const getModelShort=m=>{const mm=m||store.model||'';return mm.includes('/')?mm.split('/').pop():mm}
|
const getModelShort=m=>{const mm=m||store.model||'';return mm.includes('/')?mm.split('/').pop():mm}
|
||||||
const reflectActiveSune=()=>{const a=getActiveSune();el.settingsBtnTop.title=`Settings — ${a.name}`;el.settingsBtnTop.innerHTML=a.avatar?`<img src="${esc(a.avatar)}" alt="" class="h-8 w-8 rounded-full object-cover"/>`:'✺';icons()}
|
const renderSuneHTML=()=>{const m=el.suneHtml,h=(getActiveSune().settings.html||'').trim();m.innerHTML='';m.classList.toggle('hidden',!h);if(!h)return;m.insertAdjacentHTML('afterbegin',h);m.querySelectorAll('script').forEach(s=>{const n=document.createElement('script');[...s.attributes].forEach(a=>n.setAttribute(a.name,a.value));n.text=s.text; s.replaceWith(n)})}
|
||||||
|
const reflectActiveSune=()=>{const a=getActiveSune();el.settingsBtnTop.title=`Settings — ${a.name}`;el.settingsBtnTop.innerHTML=a.avatar?`<img src="${esc(a.avatar)}" alt="" class="h-8 w-8 rounded-full object-cover"/>`:'✺';icons();renderSuneHTML()}
|
||||||
const suneRow=a=>`<div class="relative flex items-center gap-2 px-3 py-2 ${a.pinned?'bg-yellow-50':''}"><button data-sune-id="${a.id}" class="flex-1 text-left flex items-center gap-2 ${a.id===su.getActiveId()?'font-medium':''}">${a.avatar?`<img src="${esc(a.avatar)}" alt="" class="h-6 w-6 rounded-full object-cover"/>`:`<span class="h-6 w-6 rounded-full bg-gray-200 flex items-center justify-center">✺</span>`}<span class="truncate">${a.pinned?'📌 ':''}${esc(a.name)}</span></button><button data-sune-menu="${a.id}" class="h-8 w-8 rounded hover:bg-gray-100 flex items-center justify-center" title="More"><i data-lucide="more-horizontal" class="h-4 w-4"></i></button></div>`
|
const suneRow=a=>`<div class="relative flex items-center gap-2 px-3 py-2 ${a.pinned?'bg-yellow-50':''}"><button data-sune-id="${a.id}" class="flex-1 text-left flex items-center gap-2 ${a.id===su.getActiveId()?'font-medium':''}">${a.avatar?`<img src="${esc(a.avatar)}" alt="" class="h-6 w-6 rounded-full object-cover"/>`:`<span class="h-6 w-6 rounded-full bg-gray-200 flex items-center justify-center">✺</span>`}<span class="truncate">${a.pinned?'📌 ':''}${esc(a.name)}</span></button><button data-sune-menu="${a.id}" class="h-8 w-8 rounded hover:bg-gray-100 flex items-center justify-center" title="More"><i data-lucide="more-horizontal" class="h-4 w-4"></i></button></div>`
|
||||||
const renderSidebar=()=>{const list=[...sunes].sort((a,b)=>(b.pinned-a.pinned));el.suneList.innerHTML=list.map(suneRow).join('');icons()}
|
const renderSidebar=()=>{const list=[...sunes].sort((a,b)=>(b.pinned-a.pinned));el.suneList.innerHTML=list.map(suneRow).join('');icons()}
|
||||||
function enhanceCodeBlocks(root,doHL=true){root.querySelectorAll('pre>code').forEach(code=>{if(code.textContent.length>200000)return;const pre=code.parentElement;pre.classList.add('relative','rounded-xl','border','border-gray-200');if(!pre.querySelector('.copy-btn')){const btn=document.createElement('button');btn.className='copy-btn';btn.textContent='Copy';btn.addEventListener('click',async e=>{e.stopPropagation();try{await navigator.clipboard.writeText(code.innerText);btn.textContent='Copied';setTimeout(()=>btn.textContent='Copy',1200)}catch{}});pre.appendChild(btn)}if(doHL&&window.hljs&&code.textContent.length<100000)hljs.highlightElement(code)})}
|
function enhanceCodeBlocks(root,doHL=true){root.querySelectorAll('pre>code').forEach(code=>{if(code.textContent.length>200000)return;const pre=code.parentElement;pre.classList.add('relative','rounded-xl','border','border-gray-200');if(!pre.querySelector('.copy-btn')){const btn=document.createElement('button');btn.className='copy-btn';btn.textContent='Copy';btn.addEventListener('click',async e=>{e.stopPropagation();try{await navigator.clipboard.writeText(code.innerText);btn.textContent='Copied';setTimeout(()=>btn.textContent='Copy',1200)}catch{}});pre.appendChild(btn)}if(doHL&&window.hljs&&code.textContent.length<100000)hljs.highlightElement(code)})}
|
||||||
@@ -160,7 +162,7 @@ let menuThreadId=null;const hideHistoryMenu=()=>{el.historyMenu.classList.add('h
|
|||||||
function showHistoryMenu(btn,id){menuThreadId=id;const r=btn.getBoundingClientRect();el.historyMenu.style.top=(r.bottom+4)+'px';el.historyMenu.style.left=Math.min(window.innerWidth-220,r.right-200)+'px';el.historyMenu.classList.remove('hidden');icons()}
|
function showHistoryMenu(btn,id){menuThreadId=id;const r=btn.getBoundingClientRect();el.historyMenu.style.top=(r.bottom+4)+'px';el.historyMenu.style.left=Math.min(window.innerWidth-220,r.right-200)+'px';el.historyMenu.classList.remove('hidden');icons()}
|
||||||
let menuSuneId=null;const hideSuneMenu=()=>{el.suneMenu.classList.add('hidden');menuSuneId=null}
|
let menuSuneId=null;const hideSuneMenu=()=>{el.suneMenu.classList.add('hidden');menuSuneId=null}
|
||||||
function showSuneMenu(btn,id){menuSuneId=id;const r=btn.getBoundingClientRect();el.suneMenu.style.top=(r.bottom+4)+'px';el.suneMenu.style.left=Math.min(window.innerWidth-220,r.right-200)+'px';el.suneMenu.classList.remove('hidden');icons()}
|
function showSuneMenu(btn,id){menuSuneId=id;const r=btn.getBoundingClientRect();el.suneMenu.style.top=(r.bottom+4)+'px';el.suneMenu.style.left=Math.min(window.innerWidth-220,r.right-200)+'px';el.suneMenu.classList.remove('hidden');icons()}
|
||||||
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;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.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.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.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()||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()})
|
||||||
|
|||||||
Reference in New Issue
Block a user