nexus-web-assistant 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";const n={API_URL:"https://trynexusweb.vercel.app/api/chat",API_KEY:"",MODEL:"meta-llama/llama-4-scout-17b-16e-instruct",BOT_NAME:"Nexus AI",GREETING:"👋 Hey there! I'm **Nexus AI** – your smart assistant for this page.\n\nI can help you understand and find information from the content you see here. Just ask me anything about this page and I'll assist you instantly! 🚀",SYSTEM_PROMPT:"\nYou are Nexus AI, a smart assistant. Use the page context provided in every response.\n\n**Rules:**\n- Always prioritize the given page context over general knowledge.\n- Quote specific details (headings, tables, code, lists, etc.) from the context.\n- Structure answers clearly with bullet points or headings where helpful.\n- Be crisp, professional, and friendly. Use Markdown.\n- If information is not in context, politely say so and offer to help with related topics.\n- Keep responses concise (under 600 tokens).\n ",MAX_FILE_SIZE:5242880,ALLOWED_FILE_TYPES:["image/*","application/pdf","text/*","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document"],COLORS:{bg:"#0a0a0a",panelBg:"rgba(12, 12, 12, 0.85)",border:"#2a2a2a",borderHover:"#444444",textPrimary:"#f5f5f5",textSecondary:"#a0a0a0",userBubble:"#1e1e1e",botBubble:"transparent"},EMAIL_REGEX:/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,PHONE_REGEX:/(?:\+?[\d\s\-()]{8,15})/g,BUTTON_SELECTORS:["button",'[role="button"]',".btn",".button",'[class*="btn"]','[class*="button"]','input[type="button"]','input[type="submit"]'],STAT_SELECTORS:["[data-target]",".stat-number",".count",".counter","[data-count]","[data-value]",".stats-number"],CONTACT_SELECTORS:['a[href^="mailto:"]','a[href^="tel:"]','[class*="email"]','[class*="phone"]','[class*="contact"]','[id*="email"]','[id*="phone"]','[id*="contact"]']},e=n=>document.getElementById(n);function t(n){return"undefined"!=typeof DOMPurify&&DOMPurify.sanitize?DOMPurify.sanitize(n,{ALLOWED_TAGS:["p","br","strong","em","u","s","code","pre","ul","ol","li","blockquote","h1","h2","h3","h4","h5","h6","a","img","span","div","hr","table","thead","tbody","tr","th","td","del"],ALLOWED_ATTR:["href","target","src","alt","title","class","id","style","rel","aria-label"],ALLOW_DATA_ATTR:!1}):n}function a(n){if(!n)return"";try{if("undefined"!=typeof marked&&marked.parse)return t(marked.parse(n,{breaks:!0,gfm:!0}))}catch(n){console.warn("Markdown parse failed:",n)}return t(n.replace(/\n/g,"<br>"))}function o(n,t){if(!n)return!1;const a=void 0!==t?t:!n.classList.contains("open");return n.classList.toggle("open",a),a&&setTimeout(()=>{const n=e("aiInput");n&&n.focus()},100),a}function r(n,e,t="bot",o=null,r={}){if(!n)return null;const{withRegenerate:i=!1,isError:s=!1,errorCallback:l=null}=r,c=document.createElement("div");if(c.className=`msg ${t}`,"bot"===t){const n=a(e);if(c.innerHTML=n,"undefined"!=typeof hljs&&c.querySelectorAll("pre code").forEach(n=>{hljs.highlightElement(n)}),i){const n=document.createElement("button");n.className="msg-regen-btn",n.innerHTML='<i class="fas fa-rotate-right"></i>',n.title="Regenerate response",n.setAttribute("aria-label","Regenerate"),n.addEventListener("click",n=>{n.stopPropagation();const e=new CustomEvent("regenerate-request",{detail:{messageEl:c}});document.dispatchEvent(e)}),c.appendChild(n)}}else{const n=function(n){return n?n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}(e);let t=n;o&&(t+=`<br><img src="${o}" class="image-preview" alt="attached">`),c.innerHTML=t}if(s&&l){const n=document.createElement("button");n.className="msg-retry-btn",n.innerHTML='<i class="fas fa-redo"></i> Retry',n.addEventListener("click",n=>{n.stopPropagation(),l()}),c.appendChild(n)}return n.appendChild(c),n.scrollTo({top:n.scrollHeight,behavior:"smooth"}),c}let i=null;function s(n,e){n&&(i&&(i.remove(),i=null),e&&(i=document.createElement("div"),i.className="typing-indicator",i.innerHTML="<span></span><span></span><span></span>",n.appendChild(i),n.scrollTo({top:n.scrollHeight,behavior:"smooth"})))}function l(n,e){if(!n)return;if(n.innerHTML="",!e)return;const t=e.type?.startsWith("image/")||e.dataUrl?.startsWith("data:image"),a="application/pdf"===e.type||e.name?.endsWith(".pdf"),o=e.type?.includes("document")||e.name?.endsWith(".docx")||e.name?.endsWith(".txt"),r=document.createElement("div");r.className="image-preview-pill";let i="fa-file",s="rgba(255,255,255,0.04)";var l;t?(i="fa-image",s="rgba(255,255,255,0.04)"):a?(i="fa-file-pdf",s="rgba(255,255,255,0.04)"):o&&(i="fa-file-lines",s="rgba(255,255,255,0.04)"),r.innerHTML=`\n ${t?`<img src="${e.dataUrl}" alt="preview" class="preview-thumb">`:`<i class="fas ${i}" style="font-size: 20px; color: #888;"></i>`}\n <span class="file-name">${e.name||"file"}</span>\n <span class="file-size">${l=e.size||0,l<1024?l+" B":l<1048576?(l/1024).toFixed(1)+" KB":(l/1048576).toFixed(1)+" MB"}</span>\n <button class="remove-file" id="aiRemoveFile" aria-label="Remove file">\n <i class="fas fa-times"></i>\n </button>\n `,r.style.background=s,n.appendChild(r),document.getElementById("aiRemoveFile")?.addEventListener("click",()=>{n.innerHTML="";const e=new CustomEvent("file-removed");document.dispatchEvent(e)})}const c={isOpen:!1,isProcessing:!1,attachedFile:null,conversationHistory:[],abortController:null,lastUserMessage:null,lastBotMessageEl:null,lastErrorMessageEl:null};function d(n){Object.assign(c,n)}const p="NexusAICache",u="pageData";let g=null;function m(){return new Promise((n,e)=>{if(g)return void n(g);const t=indexedDB.open(p,1);t.onupgradeneeded=n=>{const e=n.target.result;if(!e.objectStoreNames.contains(u)){const n=e.createObjectStore(u,{keyPath:"id"});n.createIndex("url","url",{unique:!1}),n.createIndex("timestamp","timestamp",{unique:!1}),console.log("📦 IndexedDB store created")}},t.onsuccess=e=>{g=e.target.result,n(g)},t.onerror=n=>{e(n.target.error)}})}async function f(n){try{const e=(await m()).transaction(u,"readwrite").objectStore(u),t=window.location.href,a={id:t,url:t,data:n,timestamp:Date.now()};return new Promise((n,t)=>{const o=e.put(a);o.onsuccess=()=>{console.log("💾 Data cached in IndexedDB"),n()},o.onerror=n=>{t(n.target.error)}})}catch(n){console.warn("IndexedDB write failed:",n)}}let b=null,h=null;function x(n,e){return new Promise((t,a)=>{const o=document.createElement("script");o.src=n,o.async=!0,e&&(o.integrity=e,o.crossOrigin="anonymous"),o.onload=t,o.onerror=a,document.head.appendChild(o)})}function y(){const e=window.__NEXUS_CONFIG||{};return{...n,...e,CONTACT_SELECTORS:e.CONTACT_SELECTORS||n.CONTACT_SELECTORS,BUTTON_SELECTORS:e.BUTTON_SELECTORS||n.BUTTON_SELECTORS,STAT_SELECTORS:e.STAT_SELECTORS||n.STAT_SELECTORS,EMAIL_REGEX:e.EMAIL_REGEX||n.EMAIL_REGEX,PHONE_REGEX:e.PHONE_REGEX||n.PHONE_REGEX}}function w(){console.log("🕷️ Advanced scraping started...");const n={title:document.title,url:window.location.href,timestamp:(new Date).toISOString(),pageType:v(),readability:null,structuredData:[],markdown:"",summary:"",metadata:{},contactInfo:{emails:[],phones:[]},buttonsInfo:[],statsInfo:[]};try{if(b){const e=document.cloneNode(!0),t=new b(e).parse();if(t){if(n.readability={title:t.title,byline:t.byline,excerpt:t.excerpt,content:t.content,textContent:t.textContent},h){const e=new h({headingStyle:"atx",codeBlockStyle:"fenced",emDelimiter:"*",bulletListMarker:"-"});e.addRule("strikethrough",{filter:["del","s","strike"],replacement:function(n){return"~~"+n+"~~"}}),n.markdown=e.turndown(t.content)}n.summary=t.excerpt||t.textContent.substring(0,300)}}}catch(e){console.warn("Readability failed, falling back to basic scraper:",e),n.readability=null}try{document.querySelectorAll('script[type="application/ld+json"]').forEach(e=>{try{const t=JSON.parse(e.textContent);n.structuredData.push(t)}catch(n){}})}catch(n){console.warn("JSON-LD extraction failed:",n)}if(n.metadata=function(){const n={},e=document.querySelector('meta[name="description"]');e&&(n.description=e.content);const t=document.querySelector('meta[name="keywords"]');t&&(n.keywords=t.content),["title","description","image","url","type","site_name"].forEach(e=>{const t=document.querySelector(`meta[property="og:${e}"]`);t&&(n[`og_${e}`]=t.content)}),["card","title","description","image"].forEach(e=>{const t=document.querySelector(`meta[name="twitter:${e}"]`);t&&(n[`twitter_${e}`]=t.content)});const a=document.querySelector('link[rel="canonical"]');return a&&(n.canonical=a.href),n}(),!n.readability){console.log("⚠️ Using fallback scraper");const e=function(){const n=document.body.cloneNode(!0);["nav","header","footer","aside",".sidebar",".navigation",".menu",".ads",".cookie-banner",".popup",".overlay","script","style","noscript","iframe"].forEach(e=>{n.querySelectorAll(e).forEach(n=>n.remove())});let e=n.textContent||"";e=e.replace(/\s+/g," ").trim();const t=e.substring(0,500)+"...";return{content:e,summary:t}}();n.markdown=e.content,n.summary=e.summary}return n.contactInfo=function(){const n=y(),e=new Set,t=new Set,a=document.body.innerText||"";return(a.match(n.EMAIL_REGEX)||[]).forEach(n=>e.add(n)),(a.match(n.PHONE_REGEX)||[]).forEach(n=>{const e=n.trim();e.length>=8&&t.add(e)}),n.CONTACT_SELECTORS.forEach(a=>{document.querySelectorAll(a).forEach(o=>{if(a.includes("mailto")){const n=o.getAttribute("href");if(n&&n.startsWith("mailto:")){const t=n.replace("mailto:","").split("?")[0];t&&e.add(t)}}else if(a.includes("tel")){const n=o.getAttribute("href");if(n&&n.startsWith("tel:")){const e=n.replace("tel:","");e&&t.add(e)}}else{const a=o.textContent.trim();a&&((a.match(n.EMAIL_REGEX)||[]).forEach(n=>e.add(n)),(a.match(n.PHONE_REGEX)||[]).forEach(n=>{n.trim().length>=8&&t.add(n.trim())}))}})}),{emails:Array.from(e),phones:Array.from(t)}}(),n.buttonsInfo=function(){const n=y(),e=[],t=new Set;return n.BUTTON_SELECTORS.forEach(n=>{document.querySelectorAll(n).forEach(n=>{let a=n.textContent.trim()||n.value||n.getAttribute("aria-label")||"";if(!a)return;const o=n.getAttribute("data-action")||n.getAttribute("onclick")||"",r=a+o;t.has(r)||(t.add(r),e.push({name:a,action:o?o.trim():"click"}))})}),e.slice(0,20)}(),n.statsInfo=function(){const n=y(),e=[],t=new Set;return n.STAT_SELECTORS.forEach(n=>{document.querySelectorAll(n).forEach(n=>{let a=n.getAttribute("data-target")||n.getAttribute("data-count")||n.getAttribute("data-value")||n.textContent.trim();if(!a)return;const o=n.closest('[class*="stat"]')||n.parentElement;let r="";if(o){const n=o.querySelector('.stat-label, .label, [class*="label"]');if(n)r=n.textContent.trim();else{const n=o.textContent.trim(),e=n.indexOf(a);if(e>-1){const t=n.substring(0,e).trim(),o=n.substring(e+a.length).trim();r=t||o}}}r||(r="Stat");const i=r+a;t.has(i)||(t.add(i),e.push({label:r,value:a}))})}),e.slice(0,20)}(),n.aiContext=E(n),console.log("✅ Advanced scraping complete"),n}function v(){const n=window.location.href,e=document.title.toLowerCase(),t=document.querySelector('meta[property="og:type"]');if(t){const n=t.content;if(n.includes("article"))return"article";if(n.includes("product"))return"product";if(n.includes("website"))return"website"}return n.includes("/blog/")||n.includes("/post/")||e.includes("blog")?"blog":n.includes("/product/")||n.includes("/shop/")?"product":n.includes("/portfolio/")||n.includes("/project/")?"portfolio":n===window.location.origin+"/"||n===window.location.origin?"homepage":"general"}function E(n){let e="";if(e+=`# 📄 ${n.title}\n\n`,e+=`**URL:** ${n.url}\n`,e+=`**Type:** ${n.pageType}\n`,e+=`**Scraped:** ${new Date(n.timestamp).toLocaleString()}\n\n`,Object.keys(n.metadata).length>0){e+="## 📋 Metadata\n";for(const[t,a]of Object.entries(n.metadata))a&&a.length>0&&(e+=`- **${t}:** ${a}\n`);e+="\n"}if(n.contactInfo&&(n.contactInfo.emails.length>0||n.contactInfo.phones.length>0)&&(e+="## 📞 Contact Information\n",n.contactInfo.emails.length>0&&(e+=`- **Emails:** ${n.contactInfo.emails.join(", ")}\n`),n.contactInfo.phones.length>0&&(e+=`- **Phones:** ${n.contactInfo.phones.join(", ")}\n`),e+="\n"),n.buttonsInfo&&n.buttonsInfo.length>0&&(e+="## 🔘 Interactive Buttons\n",n.buttonsInfo.forEach(n=>{e+=`- **${n.name}** → ${n.action}\n`}),e+="\n"),n.statsInfo&&n.statsInfo.length>0&&(e+="## 📊 Key Statistics\n",n.statsInfo.forEach(n=>{e+=`- **${n.label}:** ${n.value}\n`}),e+="\n"),n.structuredData&&n.structuredData.length>0&&(e+="## 📊 Structured Data (Schema.org)\n",n.structuredData.forEach((n,t)=>{e+=`\n### Schema ${t+1}\n`,e+=`\`\`\`json\n${JSON.stringify(n,null,2)}\n\`\`\`\n`}),e+="\n"),n.markdown){e+="## 📝 Main Content\n\n";const t=4e3,a=n.markdown.length>t?n.markdown.substring(0,t)+"... (truncated)":n.markdown;e+=a,e+="\n\n"}return n.summary&&(e+="## 📌 Summary\n\n",e+=n.summary,e+="\n\n"),e+="---\n",e+="*🤖 AI Instructions: Use this context to answer user questions about this page. Be precise, reference specific details from the content, and maintain a friendly professional tone.*\n",e}async function k(e,t,a=null,o={}){if(c.isProcessing)return;const{skipUserAdd:i=!1,onError:l=null}=o;d({isProcessing:!0});const p=document.getElementById("aiSendBtn"),g=document.getElementById("aiInput");p&&(p.disabled=!0),g&&(g.disabled=!0),i||(c.lastUserMessage={text:t,image:a},r(e,t,"user",a)),s(e,!0);const b=[];if(t&&b.push({type:"text",text:t}),a&&b.push({type:"image_url",image_url:{url:a}}),!i){if(c.conversationHistory.push({role:"user",content:t||"(image)"}),c.conversationHistory.length>11){const n=c.conversationHistory[0],e=c.conversationHistory.slice(-10);c.conversationHistory=[n,...e]}S()}const h=new AbortController;d({abortController:h});let x=!1,y="";try{const t=await async function(){let n=await async function(){try{const n=(await m()).transaction(u,"readonly").objectStore(u),e=window.location.href;return new Promise((t,a)=>{const o=n.get(e);o.onsuccess=n=>{const a=n.target.result;if(!a)return void t(null);const o=Date.now();if(o-a.timestamp>864e5)return async function(n){try{(await m()).transaction(u,"readwrite").objectStore(u).delete(n)}catch(n){console.warn("IndexedDB delete failed:",n)}}(e),void t(null);console.log(`📦 Cache hit! Age: ${Math.floor((o-a.timestamp)/6e4)} minutes`),t(a.data)},o.onerror=n=>{a(n.target.error)}})}catch(n){return console.warn("IndexedDB read failed:",n),null}}();if(n)return console.log("📦 Using cached page data"),n;console.log("🔍 Scraping page data...");const e=E(w());return await f(e),console.log("💾 Page data cached"),e}(),a=window.__NEXUS_CONFIG||n,o=[{role:"system",content:`${a.SYSTEM_PROMPT}\n\n## Current Page Context\n${t}`}];for(let n=1;n<c.conversationHistory.length-1;n++)o.push({role:c.conversationHistory[n].role,content:c.conversationHistory[n].content});o.push({role:"user",content:b});const i=await fetch(a.API_URL,{method:"POST",headers:{"Content-Type":"application/json",Origin:window.location.origin},signal:h.signal,body:JSON.stringify({nexusKey:a.API_KEY,messages:o,model:a.MODEL})});if(!i.ok){const n=await i.json().catch(()=>({}));throw new Error(`Proxy error ${i.status}: ${n.error||i.statusText}`)}const l=await i.json(),p=l.choices?.[0]?.message?.content||"Sorry, I didn't understand that.";c.conversationHistory.push({role:"assistant",content:p}),S(),s(e,!1);const g=r(e,p,"bot",null,{withRegenerate:!0});g&&d({lastBotMessageEl:g}),c.lastErrorMessageEl=null}catch(n){if("AbortError"===n.name)return void console.log("Request aborted by user");console.error("Nexus Proxy Error:",n),x=!0,y=n.message||"Something went wrong.",s(e,!1);const t=r(e,`⚠️ Oops! ${y} Please try again.`,"bot",null,{isError:!0,errorCallback:()=>{c.lastErrorMessageEl&&(c.lastErrorMessageEl.remove(),c.lastErrorMessageEl=null);const n=c.lastUserMessage;n&&k(e,n.text,n.image,{skipUserAdd:!0})}});t&&d({lastErrorMessageEl:t}),l&&l(n)}finally{if(d({isProcessing:!1,abortController:null}),p&&(p.disabled=!1),g){if(g.disabled=!1,!x){g.value="",g.style.height="auto";const n=document.getElementById("aiCharCount");n&&(n.textContent="0",n.style.color="#a0a0a0")}g.focus()}}}function S(){try{const n=c.conversationHistory.slice(1);localStorage.setItem("nexus-chat-history",JSON.stringify(n))}catch(n){}}function T(){const n=document.getElementById("ai-widget-root");if(!n)return;const e="dark"===(n.dataset.theme||"dark")?"light":"dark";n.dataset.theme=e,localStorage.setItem("nexus-theme",e),window.__NEXUS_CONFIG&&(window.__NEXUS_CONFIG.THEME=e);const t=document.getElementById("aiThemeToggle");t&&(t.innerHTML="dark"===e?'<i class="fas fa-moon"></i>':'<i class="fas fa-sun"></i>',t.title="dark"===e?"Switch to Light":"Switch to Dark"),console.log(`🌓 Theme switched to: ${e}`)}function C(n,e){return new Promise((t,a)=>{const o=document.createElement("script");o.src=n,o.async=!0,e&&(o.integrity=e,o.crossOrigin="anonymous"),o.onload=t,o.onerror=a,document.head.appendChild(o)})}function I(n,e){return new Promise((t,a)=>{const o=document.createElement("link");o.rel="stylesheet",o.href=n,e&&(o.integrity=e,o.crossOrigin="anonymous"),o.onload=t,o.onerror=a,document.head.appendChild(o)})}async function O(){const t=function(){const e=window.NexusConfig||{},t=function(){const n=window.NexusConfig||{};if(n.theme)return n.theme;const e=localStorage.getItem("nexus-theme");if(e)return e;const t=document.body;if(t.classList.contains("dark")||t.classList.contains("dark-theme")||t.classList.contains("dark-mode"))return"dark";if(t.classList.contains("light")||t.classList.contains("light-theme")||t.classList.contains("light-mode"))return"light";const a=document.documentElement.getAttribute("data-theme");if("dark"===a||"light"===a)return a;const o=document.querySelector('meta[name="theme-color"]');if(o){const n=o.content;if(n.startsWith("#")&&parseInt(n.slice(1,3),16)<100)return"dark"}return window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches,"dark"}();return{API_URL:n.API_URL,API_KEY:e.apiKey||n.API_KEY,MODEL:e.model||n.MODEL,BOT_NAME:e.botName||n.BOT_NAME,GREETING:e.greeting||n.GREETING,SYSTEM_PROMPT:e.systemPrompt||n.SYSTEM_PROMPT,THEME:t,COLORS:n.COLORS}}();window.__NEXUS_CONFIG=t,await async function(){await I("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css","sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==");const n=document.createElement("link");n.rel="stylesheet",n.href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap",document.head.appendChild(n),await C("https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.1.6/purify.min.js","sha512-jB0TkTBeQC9ZSkBqDhdmfTv1qdfbWpGE72yJ/01Srq6hEzZIz2xkz1e57p9ai7IeHMwEG7HpzG6NdptChif5Pg=="),await C("https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js","sha512-tjg8I2d6Fi0OBGz1csmr7RfI4uupYaCfL/RqhVRTS42RMGwfBsjwBGmhzhI+e2dPmyew8cFkoxnVkGvADDLvbg=="),await I("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css","sha512-rO+olRTkcf304DQBxSWxln8JXCzTHlKnIdnMUwYvQa9/Jd4cQaNkItIUj6Z4nvW1dqK0SKXLbn9h4KwZTNtAyw=="),await C("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js","sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ=="),await async function(){await Promise.all([x("https://cdnjs.cloudflare.com/ajax/libs/readability/0.4.4/Readability.min.js","sha384-YqVytsOEvlLnJ+cNHmbexthfaZ482cPdQ+GQuIZngy2l0P+HIKE7wpmcUC6Ni5iw"),x("https://cdnjs.cloudflare.com/ajax/libs/turndown/7.1.2/turndown.min.js","sha384-m6AyXEhyWRg2s2wrkDV64LGkaManYgMSAjn2U+zymzSJ42WthRSjCu1AqZJhoQV0")]),b=window.Readability,h=window.TurndownService,console.log("📚 Scraper libraries loaded")}()}(),function(){const n=document.createElement("style");n.id="ai-chat-widget-styles",n.textContent="\n #ai-widget-root {\n --bg-panel: rgba(9, 9, 11, 0.92);\n --bg-input: rgba(24, 24, 27, 0.6);\n --border-color: rgba(39, 39, 42, 0.6);\n --text-primary: #fafafa;\n --text-secondary: #a1a1aa;\n --user-bubble-bg: #27272a;\n --bot-bubble-bg: rgba(24, 24, 27, 0.6);\n --shadow-color: rgba(0, 0, 0, 0.4);\n --fab-bg: rgba(24, 24, 27, 0.8);\n --accent: #a855f7;\n --send-bg: #a855f7;\n --send-color: #fff;\n --border-hover: rgba(168, 85, 247, 0.3);\n }\n\n #ai-widget-root[data-theme=\"light\"] {\n --bg-panel: rgba(245, 245, 245, 0.92);\n --bg-input: rgba(0, 0, 0, 0.02);\n --border-color: rgba(0, 0, 0, 0.08);\n --text-primary: #111;\n --text-secondary: #555;\n --user-bubble-bg: #e0e0e0;\n --bot-bubble-bg: rgba(255, 255, 255, 0.5);\n --shadow-color: rgba(0, 0, 0, 0.05);\n --fab-bg: rgba(255, 255, 255, 0.6);\n --accent: #888;\n --send-bg: #222;\n --send-color: #fff;\n --border-hover: rgba(0, 0, 0, 0.15);\n }\n\n @keyframes slideUpFade {\n 0% { opacity: 0; transform: translateY(30px) scale(0.95); }\n 100% { opacity: 1; transform: translateY(0) scale(1); }\n }\n @keyframes pulseDot {\n 0%, 100% { transform: scale(0.8); opacity: 0.4; }\n 50% { transform: scale(1.2); opacity: 1; }\n }\n @keyframes typing {\n 0%, 80%, 100% { opacity: 0.3; transform: translateY(2px); }\n 40% { opacity: 1; transform: translateY(-2px); }\n }\n @keyframes previewPop {\n 0% { opacity: 0; transform: scale(0.8) translateY(10px); }\n 100% { opacity: 1; transform: scale(1) translateY(0); }\n }\n @keyframes fabPulse {\n 0% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0.1); }\n 70% { box-shadow: 0 0 0 16px rgba(168, 85, 247, 0); }\n 100% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0); }\n }\n\n #ai-widget-root {\n all: initial;\n font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 999999;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n pointer-events: none;\n color: var(--text-primary);\n }\n #ai-widget-root * { box-sizing: border-box; pointer-events: auto; }\n\n #ai-widget-root .fas,\n #ai-widget-root .far,\n #ai-widget-root .fab {\n font-family: 'Font Awesome 6 Free', 'Font Awesome 6 Brands' !important;\n font-weight: 900 !important;\n font-style: normal;\n font-variant: normal;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n }\n #ai-widget-root .far { font-weight: 400 !important; }\n #ai-widget-root .fab {\n font-family: 'Font Awesome 6 Brands' !important;\n font-weight: 400 !important;\n }\n\n .ai-fab {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: var(--fab-bg);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border: 1px solid var(--border-color);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--text-primary);\n transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n user-select: none;\n box-shadow: 0 4px 24px var(--shadow-color);\n position: relative;\n z-index: 10;\n will-change: transform, opacity;\n animation: fabPulse 3s infinite;\n }\n .ai-fab:hover {\n transform: scale(1.06);\n box-shadow: 0 6px 32px var(--shadow-color);\n border-color: var(--accent);\n }\n .ai-fab .bot-icon i {\n color: #fafafa !important;\n font-size: 26px !important;\n filter: none;\n }\n .ai-panel.open ~ .ai-fab {\n opacity: 0;\n transform: scale(0.8);\n pointer-events: none;\n animation: none;\n }\n\n .ai-panel {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 420px;\n max-width: calc(100vw - 48px);\n height: 620px;\n max-height: calc(100vh - 48px);\n background: var(--bg-panel);\n backdrop-filter: blur(24px);\n -webkit-backdrop-filter: blur(24px);\n border-radius: 28px;\n box-shadow: 0 16px 64px var(--shadow-color), 0 0 0 1px var(--border-color);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n opacity: 0;\n visibility: hidden;\n transform: translateY(20px) scale(0.96);\n transition: all 0.35s cubic-bezier(0.16, 1, 0.3, 1);\n border: 1px solid var(--border-color);\n }\n .ai-panel.open {\n opacity: 1;\n visibility: visible;\n transform: translateY(0) scale(1);\n }\n\n .ai-header {\n padding: 20px 24px;\n border-bottom: 1px solid var(--border-color);\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n }\n .ai-header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .ai-header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n color: var(--text-primary);\n font-weight: 600;\n font-size: 16px;\n letter-spacing: -0.3px;\n }\n .status-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #a855f7;\n animation: pulseDot 2s infinite;\n flex-shrink: 0;\n }\n .ai-theme-toggle,\n .ai-close-btn,\n .ai-clear-btn {\n background: transparent;\n border: 1px solid var(--border-color);\n color: var(--text-secondary);\n width: 32px;\n height: 32px;\n border-radius: 50%;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .ai-theme-toggle:hover,\n .ai-close-btn:hover,\n .ai-clear-btn:hover {\n background: var(--border-color);\n color: var(--text-primary);\n }\n .ai-theme-toggle:hover {\n transform: rotate(180deg) !important;\n }\n .ai-close-btn:hover {\n transform: rotate(90deg);\n }\n\n .ai-messages {\n flex: 1;\n padding: 24px 24px 16px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 20px;\n scroll-behavior: smooth;\n }\n .ai-messages::-webkit-scrollbar { width: 4px; }\n .ai-messages::-webkit-scrollbar-track { background: transparent; }\n .ai-messages::-webkit-scrollbar-thumb {\n background: var(--border-color);\n border-radius: 10px;\n }\n\n .msg {\n max-width: 85%;\n font-size: 14.5px;\n line-height: 1.7;\n word-break: break-word;\n animation: slideUpFade 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n color: var(--text-primary);\n padding: 12px 18px;\n border-radius: 18px;\n position: relative;\n box-shadow: 0 1px 4px var(--shadow-color);\n }\n .msg.user {\n align-self: flex-end;\n background: var(--user-bubble-bg);\n border: 1px solid var(--border-color);\n border-bottom-right-radius: 4px;\n }\n .msg.bot {\n align-self: flex-start;\n background: var(--bot-bubble-bg);\n border: 1px solid var(--border-color);\n border-bottom-left-radius: 4px;\n max-width: 95%;\n padding-bottom: 32px;\n }\n\n .msg.user::after {\n content: '';\n position: absolute;\n bottom: 0;\n right: -6px;\n width: 12px;\n height: 12px;\n background: var(--user-bubble-bg);\n border-radius: 0 0 12px 0;\n clip-path: polygon(0 0, 100% 0, 100% 100%);\n }\n .msg.bot::before {\n content: '';\n position: absolute;\n bottom: 0;\n left: -6px;\n width: 12px;\n height: 12px;\n background: var(--bot-bubble-bg);\n border-radius: 0 0 0 12px;\n clip-path: polygon(0 0, 100% 100%, 100% 0);\n }\n\n .msg.bot p { margin: 0 0 12px 0; }\n .msg.bot p:last-child { margin-bottom: 0; }\n .msg.bot code {\n background: rgba(39, 39, 42, 0.6);\n padding: 2px 8px;\n border-radius: 6px;\n font-family: ui-monospace, monospace;\n font-size: 0.9em;\n border: 1px solid rgba(39, 39, 42, 0.4);\n color: #e4e4e7;\n }\n .msg.bot pre {\n background: rgba(9, 9, 11, 0.4);\n padding: 16px;\n border-radius: 14px;\n overflow-x: auto;\n margin: 12px 0;\n border: 1px solid rgba(39, 39, 42, 0.4);\n }\n .msg.bot pre code { background: transparent; padding: 0; border: none; }\n .msg.bot ul, .msg.bot ol { margin: 8px 0 12px 20px; padding-left: 0; }\n .msg.bot li { margin-bottom: 6px; }\n .msg.bot a { color: #a855f7; text-decoration: none; border-bottom: 1px dotted rgba(168, 85, 247, 0.2); }\n .msg .image-preview {\n max-width: 200px;\n border-radius: 14px;\n margin-top: 8px;\n border: 1px solid var(--border-color);\n }\n\n .msg-regen-btn,\n .msg-retry-btn {\n background: transparent;\n border: 1px solid var(--border-color);\n color: var(--text-secondary);\n padding: 4px 10px;\n border-radius: 20px;\n font-size: 12px;\n cursor: pointer;\n margin-top: 8px;\n transition: all 0.2s ease;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n }\n .msg-regen-btn:hover,\n .msg-retry-btn:hover {\n background: var(--border-color);\n color: var(--text-primary);\n border-color: var(--accent);\n }\n .msg.bot .msg-regen-btn {\n position: absolute;\n bottom: 8px;\n right: 8px;\n opacity: 0.6;\n font-size: 14px;\n padding: 4px 6px;\n border-radius: 50%;\n width: 30px;\n height: 30px;\n justify-content: center;\n background: var(--bg-panel);\n margin-top: 0;\n border: 1px solid var(--border-color);\n }\n .msg.bot .msg-regen-btn:hover {\n opacity: 1;\n }\n .msg-retry-btn {\n background: rgba(239, 68, 68, 0.1);\n border-color: rgba(239, 68, 68, 0.3);\n color: #ef4444;\n margin-left: 4px;\n }\n .msg-retry-btn:hover {\n background: rgba(239, 68, 68, 0.2);\n border-color: #ef4444;\n color: #ef4444;\n }\n\n .ai-input-area {\n padding: 12px 20px 20px;\n background: transparent;\n flex-shrink: 0;\n border-top: 1px solid var(--border-color);\n }\n .ai-input-container {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n background: var(--bg-input);\n border: 1px solid var(--border-color);\n border-radius: 20px;\n padding: 4px 4px 4px 16px;\n transition: all 0.25s ease;\n min-height: 48px;\n }\n .ai-input-container:focus-within {\n border-color: var(--accent);\n box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.08);\n }\n .ai-input-container textarea {\n flex: 1;\n background: transparent;\n border: none;\n color: var(--text-primary);\n font-size: 14px;\n outline: none;\n font-family: inherit;\n padding: 10px 0;\n resize: none;\n max-height: 150px;\n line-height: 1.6;\n min-height: 28px;\n scrollbar-width: none;\n }\n .ai-input-container textarea::placeholder {\n color: var(--text-secondary);\n font-weight: 400;\n }\n\n .icon-btn {\n background: transparent;\n border: none;\n color: var(--text-secondary);\n width: 38px;\n height: 38px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n align-self: flex-end;\n margin-bottom: 2px;\n }\n .icon-btn:hover {\n color: var(--text-primary);\n background: var(--border-color);\n transform: scale(1.05);\n }\n .icon-btn:active { transform: scale(0.92); }\n\n .send-btn {\n background: var(--send-bg);\n color: var(--send-color);\n width: 38px;\n height: 38px;\n align-self: flex-end;\n margin-bottom: 2px;\n box-shadow: 0 2px 8px var(--shadow-color);\n transition: all 0.25s ease;\n border: none;\n }\n .send-btn:hover {\n transform: scale(1.06);\n box-shadow: 0 4px 12px var(--shadow-color);\n }\n .send-btn:active { transform: scale(0.92); }\n .send-btn:disabled {\n background: rgba(39, 39, 42, 0.6);\n color: var(--text-secondary);\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n }\n\n .ai-input-footer {\n display: flex;\n justify-content: flex-end;\n padding: 4px 6px 0;\n min-height: 20px;\n }\n .ai-char-count {\n font-size: 11px;\n color: var(--text-secondary);\n font-weight: 500;\n transition: color 0.2s;\n opacity: 0.4;\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n }\n\n #aiPreviewContainer {\n margin-bottom: 8px;\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n .image-preview-pill {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n background: rgba(24, 24, 27, 0.8);\n border: 1px solid var(--border-color);\n border-radius: 14px;\n padding: 6px 12px 6px 6px;\n animation: previewPop 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n box-shadow: 0 2px 12px var(--shadow-color);\n transition: all 0.2s;\n max-width: 100%;\n }\n .image-preview-pill:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px var(--shadow-color);\n }\n .image-preview-pill .preview-thumb {\n width: 32px;\n height: 32px;\n border-radius: 10px;\n object-fit: cover;\n border: 1px solid var(--border-color);\n }\n .image-preview-pill .file-name {\n font-size: 12px;\n color: var(--text-primary);\n max-width: 150px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n }\n .image-preview-pill .file-size {\n font-size: 10px;\n color: var(--text-secondary);\n opacity: 0.6;\n }\n .image-preview-pill .remove-file {\n background: rgba(39, 39, 42, 0.6);\n border: none;\n color: var(--text-secondary);\n cursor: pointer;\n font-size: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 4px;\n border-radius: 50%;\n transition: all 0.2s;\n margin-left: 2px;\n width: 26px;\n height: 26px;\n }\n .image-preview-pill .remove-file:hover {\n color: #ef4444;\n background: rgba(239,68,68,0.12);\n transform: scale(1.1);\n }\n\n .typing-indicator {\n display: flex;\n gap: 6px;\n padding: 12px 0;\n align-self: flex-start;\n background: rgba(24, 24, 27, 0.6);\n padding: 10px 16px;\n border-radius: 18px;\n border: 1px solid var(--border-color);\n }\n .typing-indicator span {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #a855f7;\n animation: typing 1.4s infinite;\n }\n .typing-indicator span:nth-child(2) { animation-delay: 0.2s; }\n .typing-indicator span:nth-child(3) { animation-delay: 0.4s; }\n\n @media (max-width: 480px) {\n .ai-panel {\n width: calc(100vw - 32px);\n right: 16px;\n height: 80vh;\n max-height: calc(100vh - 48px);\n border-radius: 20px;\n }\n .ai-fab {\n width: 52px;\n height: 52px;\n }\n .ai-fab .bot-icon { font-size: 22px; }\n .ai-input-area {\n padding: 8px 14px 14px;\n }\n .ai-input-container {\n border-radius: 16px;\n padding: 2px 2px 2px 12px;\n min-height: 42px;\n }\n .ai-input-container textarea { font-size: 13px; padding: 8px 0; }\n .icon-btn { width: 32px; height: 32px; }\n .send-btn { width: 32px; height: 32px; }\n .image-preview-pill .file-name { max-width: 100px; }\n .msg.bot {\n padding-bottom: 28px;\n }\n }\n ",document.head.appendChild(n)}(),function(){const t=window.__NEXUS_CONFIG?.BOT_NAME||n.BOT_NAME,o=a(window.__NEXUS_CONFIG?.GREETING||n.GREETING),r=document.createElement("div");r.id="ai-widget-root",r.innerHTML=`\n <div class="ai-panel" id="aiPanel">\n <div class="ai-header">\n <div class="ai-header-title">\n <span class="status-dot"></span>\n ${t}\n </div>\n <div class="ai-header-actions">\n <button class="ai-theme-toggle" id="aiThemeToggle" aria-label="Toggle theme">\n <i class="fas fa-moon"></i>\n </button>\n <button class="ai-clear-btn" id="aiClearBtn" aria-label="Clear chat">\n <i class="fas fa-trash"></i>\n </button>\n <button class="ai-close-btn" id="aiCloseBtn" aria-label="Close chat">\n <i class="fas fa-xmark"></i>\n </button>\n </div>\n </div>\n <div class="ai-messages" id="aiMessages">\n <div class="msg bot">\n ${o}\n </div>\n </div>\n <div class="ai-input-area" id="aiInputArea">\n <div id="aiPreviewContainer"></div>\n <div class="ai-input-container">\n <button class="icon-btn" id="aiAttachBtn" aria-label="Attach image or file">\n <i class="fas fa-paperclip"></i>\n </button>\n <textarea \n id="aiInput" \n placeholder="Message..." \n rows="1"\n autocomplete="off"\n spellcheck="true"\n ></textarea>\n <button class="icon-btn send-btn" id="aiSendBtn">\n <i class="fas fa-arrow-up"></i>\n </button>\n </div>\n <div class="ai-input-footer">\n <span class="ai-char-count" id="aiCharCount">0</span>\n </div>\n </div>\n </div>\n <button class="ai-fab" id="aiFab" aria-label="Open AI Chat">\n <span class="bot-icon">\n <i class="fas fa-robot" style="color: #ffffff !important; font-size: 22px;"></i>\n </span>\n </button>\n `,document.body.appendChild(r);const i=e("aiInput");i&&i.addEventListener("input",()=>{!function(n){n.style.height="auto",n.style.height=Math.min(n.scrollHeight,150)+"px"}(i),function(n){const t=e("aiCharCount");if(t){const e=n.value.length;t.textContent=e>0?`${e}`:"0",t.style.color=e>500?"#ef4444":"#a0a0a0"}}(i)})}();const i=document.getElementById("ai-widget-root");i&&(i.dataset.theme=t.THEME||"dark");const s=document.getElementById("aiThemeToggle");if(s){const n="dark"===t.THEME;s.innerHTML=n?'<i class="fas fa-moon"></i>':'<i class="fas fa-sun"></i>',s.title=n?"Switch to Light":"Switch to Dark",s.addEventListener("click",T)}const g=e("aiPanel"),y=e("aiMessages"),v=e("aiFab"),S=e("aiCloseBtn"),O=e("aiSendBtn"),L=e("aiInput"),M=e("aiAttachBtn"),A=e("aiPreviewContainer"),_=e("aiClearBtn");_&&_.addEventListener("click",()=>{if(confirm("Clear all chat messages?")){y.innerHTML="";const e=function(n){if(!n)return"";try{if("undefined"!=typeof marked&&marked.parse){const e=marked.parse(n,{breaks:!0,gfm:!0});return"undefined"!=typeof DOMPurify&&DOMPurify.sanitize?DOMPurify.sanitize(e):e}}catch(n){console.warn("Markdown parse failed:",n)}return n.replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br>")}(window.__NEXUS_CONFIG?.GREETING||n.GREETING),a=document.createElement("div");a.className="msg bot",a.innerHTML=e,y.appendChild(a),c.conversationHistory=[{role:"system",content:t.SYSTEM_PROMPT}],function(){try{localStorage.removeItem("nexus-chat-history")}catch{}}(),d({lastUserMessage:null,lastBotMessageEl:null,lastErrorMessageEl:null})}}),function(n){let e=window.location.href;new MutationObserver(()=>{window.location.href!==e&&(e=window.location.href,console.log("🔄 Page navigation detected"),n())}).observe(document.body,{childList:!0,subtree:!1}),window.addEventListener("popstate",()=>{setTimeout(()=>{window.location.href!==e&&(e=window.location.href,n())},100)})}(()=>{console.log("🔄 Page changed, refreshing context..."),async function(){console.log("🔄 Forcing page context refresh...");const n=E(w());await f(n),console.log("✅ Page context refreshed")}(),r(y,"🔄 Page context updated!","bot")});const P=document.createElement("input");P.type="file";const R=n.ALLOWED_FILE_TYPES||["image/*"];function N(){c.abortController&&(c.abortController.abort(),d({abortController:null})),d({isOpen:o(g,!1)})}P.accept=R.join(","),P.style.display="none",P.id="aiFileInput",document.body.appendChild(P),M?.addEventListener("click",()=>P.click()),P.addEventListener("change",n=>{const e=n.target.files?.[0];if(!e)return;if(!R.some(n=>{if(n.endsWith("/*")){const t=n.slice(0,-2);return e.type.startsWith(t)}return e.type===n||e.name.endsWith(n.slice(1))}))return void alert("Please select a valid file type.");const t=new FileReader;t.onload=n=>{const t={dataUrl:n.target.result,name:e.name,type:e.type,size:e.size};d({attachedFile:t}),l(A,t);const a=document.getElementById("aiRemoveFile");a&&a.addEventListener("click",()=>{d({attachedFile:null}),l(A,null),L?.focus()}),L?.focus()},t.readAsDataURL(e),n.target.value=""}),v?.addEventListener("click",()=>{d({isOpen:o(g,!0)})}),S?.addEventListener("click",N),document.addEventListener("click",n=>{const e=document.getElementById("ai-widget-root");e&&c.isOpen&&!e.contains(n.target)&&N()});const B=()=>{const n=L?.value.trim();if(!n&&!c.attachedFile)return;if(c.isProcessing)return;c.attachedFile;const e=c.attachedFile?.dataUrl||null;d({attachedFile:null,lastUserMessage:{text:n,image:e}}),L.value="",L.style.height="auto",l(A,null),k(y,n,e)};O?.addEventListener("click",B),L?.addEventListener("keydown",n=>{"Enter"!==n.key||n.shiftKey||(n.preventDefault(),B())}),document.addEventListener("regenerate-request",n=>{const{messageEl:e}=n.detail;if(!e)return;if(c.isProcessing)return;const t=c.conversationHistory,a=t.length-1;if(a<0||"assistant"!==t[a].role)return;const o=a-1;if(o<0||"user"!==t[o].role)return;const r=t[o].content;t.pop(),e.remove(),c.lastBotMessageEl===e&&d({lastBotMessageEl:null}),k(y,r,null,{skipUserAdd:!0})});const j=function(){try{const n=localStorage.getItem("nexus-chat-history");return n?JSON.parse(n):null}catch{return null}}();j&&j.length>0&&(c.conversationHistory=[{role:"system",content:t.SYSTEM_PROMPT}],j.forEach(n=>{if("user"===n.role)r(y,n.content,"user");else if("assistant"===n.role){const e=r(y,n.content,"bot",null,{withRegenerate:!0});e&&n===j[j.length-1]&&d({lastBotMessageEl:e})}c.conversationHistory.push(n)}));const H=await async function(){try{const n=(await m()).transaction(u,"readonly").objectStore(u);return new Promise(e=>{const t=n.count();t.onsuccess=()=>{e({totalEntries:t.result,database:p,version:1})},t.onerror=()=>e(null)})}catch{return null}}();console.log("📊 Cache Stats:",H||"No cache yet"),console.log("✨ Nexus AI v2.0 initialized with theme:",t.THEME)}c.conversationHistory=[{role:"system",content:n.SYSTEM_PROMPT}],"loading"===document.readyState?document.addEventListener("DOMContentLoaded",O):O()})();
|
|
1
|
+
(()=>{"use strict";const n={API_URL:"https://www.trynexus.site/api/chat",API_KEY:"",MODEL:"meta-llama/llama-4-scout-17b-16e-instruct",BOT_NAME:"Nexus AI",GREETING:"👋 Hey there! I'm **Nexus AI** – your smart assistant for this page.\n\nI can help you understand and find information from the content you see here. Just ask me anything about this page and I'll assist you instantly! 🚀",SYSTEM_PROMPT:"\nYou are Nexus AI, a smart assistant. Use the page context provided in every response.\n\n**Rules:**\n- Always prioritize the given page context over general knowledge.\n- Quote specific details (headings, tables, code, lists, etc.) from the context.\n- Structure answers clearly with bullet points or headings where helpful.\n- Be crisp, professional, and friendly. Use Markdown.\n- If information is not in context, politely say so and offer to help with related topics.\n- Keep responses concise (under 600 tokens).\n ",MAX_FILE_SIZE:5242880,ALLOWED_FILE_TYPES:["image/*","application/pdf","text/*","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document"],COLORS:{bg:"#0a0a0a",panelBg:"rgba(12, 12, 12, 0.85)",border:"#2a2a2a",borderHover:"#444444",textPrimary:"#f5f5f5",textSecondary:"#a0a0a0",userBubble:"#1e1e1e",botBubble:"transparent"},EMAIL_REGEX:/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,PHONE_REGEX:/(?:\+?[\d\s\-()]{8,15})/g,BUTTON_SELECTORS:["button",'[role="button"]',".btn",".button",'[class*="btn"]','[class*="button"]','input[type="button"]','input[type="submit"]'],STAT_SELECTORS:["[data-target]",".stat-number",".count",".counter","[data-count]","[data-value]",".stats-number"],CONTACT_SELECTORS:['a[href^="mailto:"]','a[href^="tel:"]','[class*="email"]','[class*="phone"]','[class*="contact"]','[id*="email"]','[id*="phone"]','[id*="contact"]']},e=n=>document.getElementById(n);function t(n){return"undefined"!=typeof DOMPurify&&DOMPurify.sanitize?DOMPurify.sanitize(n,{ALLOWED_TAGS:["p","br","strong","em","u","s","code","pre","ul","ol","li","blockquote","h1","h2","h3","h4","h5","h6","a","img","span","div","hr","table","thead","tbody","tr","th","td","del"],ALLOWED_ATTR:["href","target","src","alt","title","class","id","style","rel","aria-label"],ALLOW_DATA_ATTR:!1}):n}function a(n){if(!n)return"";try{if("undefined"!=typeof marked&&marked.parse)return t(marked.parse(n,{breaks:!0,gfm:!0}))}catch(n){console.warn("Markdown parse failed:",n)}return t(n.replace(/\n/g,"<br>"))}function o(n,t){if(!n)return!1;const a=void 0!==t?t:!n.classList.contains("open");return n.classList.toggle("open",a),a&&setTimeout(()=>{const n=e("aiInput");n&&n.focus()},100),a}function r(n,e,t="bot",o=null,r={}){if(!n)return null;const{withRegenerate:i=!1,isError:s=!1,errorCallback:l=null}=r,c=document.createElement("div");if(c.className=`msg ${t}`,"bot"===t){const n=a(e);if(c.innerHTML=n,"undefined"!=typeof hljs&&c.querySelectorAll("pre code").forEach(n=>{hljs.highlightElement(n)}),i){const n=document.createElement("button");n.className="msg-regen-btn",n.innerHTML='<i class="fas fa-rotate-right"></i>',n.title="Regenerate response",n.setAttribute("aria-label","Regenerate"),n.addEventListener("click",n=>{n.stopPropagation();const e=new CustomEvent("regenerate-request",{detail:{messageEl:c}});document.dispatchEvent(e)}),c.appendChild(n)}}else{const n=function(n){return n?n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}(e);let t=n;o&&(t+=`<br><img src="${o}" class="image-preview" alt="attached">`),c.innerHTML=t}if(s&&l){const n=document.createElement("button");n.className="msg-retry-btn",n.innerHTML='<i class="fas fa-redo"></i> Retry',n.addEventListener("click",n=>{n.stopPropagation(),l()}),c.appendChild(n)}return n.appendChild(c),n.scrollTo({top:n.scrollHeight,behavior:"smooth"}),c}let i=null;function s(n,e){n&&(i&&(i.remove(),i=null),e&&(i=document.createElement("div"),i.className="typing-indicator",i.innerHTML="<span></span><span></span><span></span>",n.appendChild(i),n.scrollTo({top:n.scrollHeight,behavior:"smooth"})))}function l(n,e){if(!n)return;if(n.innerHTML="",!e)return;const t=e.type?.startsWith("image/")||e.dataUrl?.startsWith("data:image"),a="application/pdf"===e.type||e.name?.endsWith(".pdf"),o=e.type?.includes("document")||e.name?.endsWith(".docx")||e.name?.endsWith(".txt"),r=document.createElement("div");r.className="image-preview-pill";let i="fa-file",s="rgba(255,255,255,0.04)";var l;t?(i="fa-image",s="rgba(255,255,255,0.04)"):a?(i="fa-file-pdf",s="rgba(255,255,255,0.04)"):o&&(i="fa-file-lines",s="rgba(255,255,255,0.04)"),r.innerHTML=`\n ${t?`<img src="${e.dataUrl}" alt="preview" class="preview-thumb">`:`<i class="fas ${i}" style="font-size: 20px; color: #888;"></i>`}\n <span class="file-name">${e.name||"file"}</span>\n <span class="file-size">${l=e.size||0,l<1024?l+" B":l<1048576?(l/1024).toFixed(1)+" KB":(l/1048576).toFixed(1)+" MB"}</span>\n <button class="remove-file" id="aiRemoveFile" aria-label="Remove file">\n <i class="fas fa-times"></i>\n </button>\n `,r.style.background=s,n.appendChild(r),document.getElementById("aiRemoveFile")?.addEventListener("click",()=>{n.innerHTML="";const e=new CustomEvent("file-removed");document.dispatchEvent(e)})}const c={isOpen:!1,isProcessing:!1,attachedFile:null,conversationHistory:[],abortController:null,lastUserMessage:null,lastBotMessageEl:null,lastErrorMessageEl:null};function d(n){Object.assign(c,n)}const p="NexusAICache",u="pageData";let g=null;function m(){return new Promise((n,e)=>{if(g)return void n(g);const t=indexedDB.open(p,1);t.onupgradeneeded=n=>{const e=n.target.result;if(!e.objectStoreNames.contains(u)){const n=e.createObjectStore(u,{keyPath:"id"});n.createIndex("url","url",{unique:!1}),n.createIndex("timestamp","timestamp",{unique:!1}),console.log("📦 IndexedDB store created")}},t.onsuccess=e=>{g=e.target.result,n(g)},t.onerror=n=>{e(n.target.error)}})}async function f(n){try{const e=(await m()).transaction(u,"readwrite").objectStore(u),t=window.location.href,a={id:t,url:t,data:n,timestamp:Date.now()};return new Promise((n,t)=>{const o=e.put(a);o.onsuccess=()=>{console.log("💾 Data cached in IndexedDB"),n()},o.onerror=n=>{t(n.target.error)}})}catch(n){console.warn("IndexedDB write failed:",n)}}let b=null,h=null;function x(n,e){return new Promise((t,a)=>{const o=document.createElement("script");o.src=n,o.async=!0,e&&(o.integrity=e,o.crossOrigin="anonymous"),o.onload=t,o.onerror=a,document.head.appendChild(o)})}function y(){const e=window.__NEXUS_CONFIG||{};return{...n,...e,CONTACT_SELECTORS:e.CONTACT_SELECTORS||n.CONTACT_SELECTORS,BUTTON_SELECTORS:e.BUTTON_SELECTORS||n.BUTTON_SELECTORS,STAT_SELECTORS:e.STAT_SELECTORS||n.STAT_SELECTORS,EMAIL_REGEX:e.EMAIL_REGEX||n.EMAIL_REGEX,PHONE_REGEX:e.PHONE_REGEX||n.PHONE_REGEX}}function w(){console.log("🕷️ Advanced scraping started...");const n={title:document.title,url:window.location.href,timestamp:(new Date).toISOString(),pageType:v(),readability:null,structuredData:[],markdown:"",summary:"",metadata:{},contactInfo:{emails:[],phones:[]},buttonsInfo:[],statsInfo:[]};try{if(b){const e=document.cloneNode(!0),t=new b(e).parse();if(t){if(n.readability={title:t.title,byline:t.byline,excerpt:t.excerpt,content:t.content,textContent:t.textContent},h){const e=new h({headingStyle:"atx",codeBlockStyle:"fenced",emDelimiter:"*",bulletListMarker:"-"});e.addRule("strikethrough",{filter:["del","s","strike"],replacement:function(n){return"~~"+n+"~~"}}),n.markdown=e.turndown(t.content)}n.summary=t.excerpt||t.textContent.substring(0,300)}}}catch(e){console.warn("Readability failed, falling back to basic scraper:",e),n.readability=null}try{document.querySelectorAll('script[type="application/ld+json"]').forEach(e=>{try{const t=JSON.parse(e.textContent);n.structuredData.push(t)}catch(n){}})}catch(n){console.warn("JSON-LD extraction failed:",n)}if(n.metadata=function(){const n={},e=document.querySelector('meta[name="description"]');e&&(n.description=e.content);const t=document.querySelector('meta[name="keywords"]');t&&(n.keywords=t.content),["title","description","image","url","type","site_name"].forEach(e=>{const t=document.querySelector(`meta[property="og:${e}"]`);t&&(n[`og_${e}`]=t.content)}),["card","title","description","image"].forEach(e=>{const t=document.querySelector(`meta[name="twitter:${e}"]`);t&&(n[`twitter_${e}`]=t.content)});const a=document.querySelector('link[rel="canonical"]');return a&&(n.canonical=a.href),n}(),!n.readability){console.log("⚠️ Using fallback scraper");const e=function(){const n=document.body.cloneNode(!0);["nav","header","footer","aside",".sidebar",".navigation",".menu",".ads",".cookie-banner",".popup",".overlay","script","style","noscript","iframe"].forEach(e=>{n.querySelectorAll(e).forEach(n=>n.remove())});let e=n.textContent||"";e=e.replace(/\s+/g," ").trim();const t=e.substring(0,500)+"...";return{content:e,summary:t}}();n.markdown=e.content,n.summary=e.summary}return n.contactInfo=function(){const n=y(),e=new Set,t=new Set,a=document.body.innerText||"";return(a.match(n.EMAIL_REGEX)||[]).forEach(n=>e.add(n)),(a.match(n.PHONE_REGEX)||[]).forEach(n=>{const e=n.trim();e.length>=8&&t.add(e)}),n.CONTACT_SELECTORS.forEach(a=>{document.querySelectorAll(a).forEach(o=>{if(a.includes("mailto")){const n=o.getAttribute("href");if(n&&n.startsWith("mailto:")){const t=n.replace("mailto:","").split("?")[0];t&&e.add(t)}}else if(a.includes("tel")){const n=o.getAttribute("href");if(n&&n.startsWith("tel:")){const e=n.replace("tel:","");e&&t.add(e)}}else{const a=o.textContent.trim();a&&((a.match(n.EMAIL_REGEX)||[]).forEach(n=>e.add(n)),(a.match(n.PHONE_REGEX)||[]).forEach(n=>{n.trim().length>=8&&t.add(n.trim())}))}})}),{emails:Array.from(e),phones:Array.from(t)}}(),n.buttonsInfo=function(){const n=y(),e=[],t=new Set;return n.BUTTON_SELECTORS.forEach(n=>{document.querySelectorAll(n).forEach(n=>{let a=n.textContent.trim()||n.value||n.getAttribute("aria-label")||"";if(!a)return;const o=n.getAttribute("data-action")||n.getAttribute("onclick")||"",r=a+o;t.has(r)||(t.add(r),e.push({name:a,action:o?o.trim():"click"}))})}),e.slice(0,20)}(),n.statsInfo=function(){const n=y(),e=[],t=new Set;return n.STAT_SELECTORS.forEach(n=>{document.querySelectorAll(n).forEach(n=>{let a=n.getAttribute("data-target")||n.getAttribute("data-count")||n.getAttribute("data-value")||n.textContent.trim();if(!a)return;const o=n.closest('[class*="stat"]')||n.parentElement;let r="";if(o){const n=o.querySelector('.stat-label, .label, [class*="label"]');if(n)r=n.textContent.trim();else{const n=o.textContent.trim(),e=n.indexOf(a);if(e>-1){const t=n.substring(0,e).trim(),o=n.substring(e+a.length).trim();r=t||o}}}r||(r="Stat");const i=r+a;t.has(i)||(t.add(i),e.push({label:r,value:a}))})}),e.slice(0,20)}(),n.aiContext=E(n),console.log("✅ Advanced scraping complete"),n}function v(){const n=window.location.href,e=document.title.toLowerCase(),t=document.querySelector('meta[property="og:type"]');if(t){const n=t.content;if(n.includes("article"))return"article";if(n.includes("product"))return"product";if(n.includes("website"))return"website"}return n.includes("/blog/")||n.includes("/post/")||e.includes("blog")?"blog":n.includes("/product/")||n.includes("/shop/")?"product":n.includes("/portfolio/")||n.includes("/project/")?"portfolio":n===window.location.origin+"/"||n===window.location.origin?"homepage":"general"}function E(n){let e="";if(e+=`# 📄 ${n.title}\n\n`,e+=`**URL:** ${n.url}\n`,e+=`**Type:** ${n.pageType}\n`,e+=`**Scraped:** ${new Date(n.timestamp).toLocaleString()}\n\n`,Object.keys(n.metadata).length>0){e+="## 📋 Metadata\n";for(const[t,a]of Object.entries(n.metadata))a&&a.length>0&&(e+=`- **${t}:** ${a}\n`);e+="\n"}if(n.contactInfo&&(n.contactInfo.emails.length>0||n.contactInfo.phones.length>0)&&(e+="## 📞 Contact Information\n",n.contactInfo.emails.length>0&&(e+=`- **Emails:** ${n.contactInfo.emails.join(", ")}\n`),n.contactInfo.phones.length>0&&(e+=`- **Phones:** ${n.contactInfo.phones.join(", ")}\n`),e+="\n"),n.buttonsInfo&&n.buttonsInfo.length>0&&(e+="## 🔘 Interactive Buttons\n",n.buttonsInfo.forEach(n=>{e+=`- **${n.name}** → ${n.action}\n`}),e+="\n"),n.statsInfo&&n.statsInfo.length>0&&(e+="## 📊 Key Statistics\n",n.statsInfo.forEach(n=>{e+=`- **${n.label}:** ${n.value}\n`}),e+="\n"),n.structuredData&&n.structuredData.length>0&&(e+="## 📊 Structured Data (Schema.org)\n",n.structuredData.forEach((n,t)=>{e+=`\n### Schema ${t+1}\n`,e+=`\`\`\`json\n${JSON.stringify(n,null,2)}\n\`\`\`\n`}),e+="\n"),n.markdown){e+="## 📝 Main Content\n\n";const t=4e3,a=n.markdown.length>t?n.markdown.substring(0,t)+"... (truncated)":n.markdown;e+=a,e+="\n\n"}return n.summary&&(e+="## 📌 Summary\n\n",e+=n.summary,e+="\n\n"),e+="---\n",e+="*🤖 AI Instructions: Use this context to answer user questions about this page. Be precise, reference specific details from the content, and maintain a friendly professional tone.*\n",e}async function k(e,t,a=null,o={}){if(c.isProcessing)return;const{skipUserAdd:i=!1,onError:l=null}=o;d({isProcessing:!0});const p=document.getElementById("aiSendBtn"),g=document.getElementById("aiInput");p&&(p.disabled=!0),g&&(g.disabled=!0),i||(c.lastUserMessage={text:t,image:a},r(e,t,"user",a)),s(e,!0);const b=[];if(t&&b.push({type:"text",text:t}),a&&b.push({type:"image_url",image_url:{url:a}}),!i){if(c.conversationHistory.push({role:"user",content:t||"(image)"}),c.conversationHistory.length>11){const n=c.conversationHistory[0],e=c.conversationHistory.slice(-10);c.conversationHistory=[n,...e]}S()}const h=new AbortController;d({abortController:h});let x=!1,y="";try{const t=await async function(){let n=await async function(){try{const n=(await m()).transaction(u,"readonly").objectStore(u),e=window.location.href;return new Promise((t,a)=>{const o=n.get(e);o.onsuccess=n=>{const a=n.target.result;if(!a)return void t(null);const o=Date.now();if(o-a.timestamp>864e5)return async function(n){try{(await m()).transaction(u,"readwrite").objectStore(u).delete(n)}catch(n){console.warn("IndexedDB delete failed:",n)}}(e),void t(null);console.log(`📦 Cache hit! Age: ${Math.floor((o-a.timestamp)/6e4)} minutes`),t(a.data)},o.onerror=n=>{a(n.target.error)}})}catch(n){return console.warn("IndexedDB read failed:",n),null}}();if(n)return console.log("📦 Using cached page data"),n;console.log("🔍 Scraping page data...");const e=E(w());return await f(e),console.log("💾 Page data cached"),e}(),a=window.__NEXUS_CONFIG||n,o=[{role:"system",content:`${a.SYSTEM_PROMPT}\n\n## Current Page Context\n${t}`}];for(let n=1;n<c.conversationHistory.length-1;n++)o.push({role:c.conversationHistory[n].role,content:c.conversationHistory[n].content});o.push({role:"user",content:b});const i=await fetch(a.API_URL,{method:"POST",headers:{"Content-Type":"application/json",Origin:window.location.origin},signal:h.signal,body:JSON.stringify({nexusKey:a.API_KEY,messages:o,model:a.MODEL})});if(!i.ok){const n=await i.json().catch(()=>({}));throw new Error(`Proxy error ${i.status}: ${n.error||i.statusText}`)}const l=await i.json(),p=l.choices?.[0]?.message?.content||"Sorry, I didn't understand that.";c.conversationHistory.push({role:"assistant",content:p}),S(),s(e,!1);const g=r(e,p,"bot",null,{withRegenerate:!0});g&&d({lastBotMessageEl:g}),c.lastErrorMessageEl=null}catch(n){if("AbortError"===n.name)return void console.log("Request aborted by user");console.error("Nexus Proxy Error:",n),x=!0,y=n.message||"Something went wrong.",s(e,!1);const t=r(e,`⚠️ Oops! ${y} Please try again.`,"bot",null,{isError:!0,errorCallback:()=>{c.lastErrorMessageEl&&(c.lastErrorMessageEl.remove(),c.lastErrorMessageEl=null);const n=c.lastUserMessage;n&&k(e,n.text,n.image,{skipUserAdd:!0})}});t&&d({lastErrorMessageEl:t}),l&&l(n)}finally{if(d({isProcessing:!1,abortController:null}),p&&(p.disabled=!1),g){if(g.disabled=!1,!x){g.value="",g.style.height="auto";const n=document.getElementById("aiCharCount");n&&(n.textContent="0",n.style.color="#a0a0a0")}g.focus()}}}function S(){try{const n=c.conversationHistory.slice(1);localStorage.setItem("nexus-chat-history",JSON.stringify(n))}catch(n){}}function T(){const n=document.getElementById("ai-widget-root");if(!n)return;const e="dark"===(n.dataset.theme||"dark")?"light":"dark";n.dataset.theme=e,localStorage.setItem("nexus-theme",e),window.__NEXUS_CONFIG&&(window.__NEXUS_CONFIG.THEME=e);const t=document.getElementById("aiThemeToggle");t&&(t.innerHTML="dark"===e?'<i class="fas fa-moon"></i>':'<i class="fas fa-sun"></i>',t.title="dark"===e?"Switch to Light":"Switch to Dark"),console.log(`🌓 Theme switched to: ${e}`)}function C(n,e){return new Promise((t,a)=>{const o=document.createElement("script");o.src=n,o.async=!0,e&&(o.integrity=e,o.crossOrigin="anonymous"),o.onload=t,o.onerror=a,document.head.appendChild(o)})}function I(n,e){return new Promise((t,a)=>{const o=document.createElement("link");o.rel="stylesheet",o.href=n,e&&(o.integrity=e,o.crossOrigin="anonymous"),o.onload=t,o.onerror=a,document.head.appendChild(o)})}async function O(){const t=function(){const e=window.NexusConfig||{},t=function(){const n=window.NexusConfig||{};if(n.theme)return n.theme;const e=localStorage.getItem("nexus-theme");if(e)return e;const t=document.body;if(t.classList.contains("dark")||t.classList.contains("dark-theme")||t.classList.contains("dark-mode"))return"dark";if(t.classList.contains("light")||t.classList.contains("light-theme")||t.classList.contains("light-mode"))return"light";const a=document.documentElement.getAttribute("data-theme");if("dark"===a||"light"===a)return a;const o=document.querySelector('meta[name="theme-color"]');if(o){const n=o.content;if(n.startsWith("#")&&parseInt(n.slice(1,3),16)<100)return"dark"}return window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches,"dark"}();return{API_URL:n.API_URL,API_KEY:e.apiKey||n.API_KEY,MODEL:e.model||n.MODEL,BOT_NAME:e.botName||n.BOT_NAME,GREETING:e.greeting||n.GREETING,SYSTEM_PROMPT:e.systemPrompt||n.SYSTEM_PROMPT,THEME:t,COLORS:n.COLORS}}();window.__NEXUS_CONFIG=t,await async function(){await I("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css","sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==");const n=document.createElement("link");n.rel="stylesheet",n.href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap",document.head.appendChild(n),await C("https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.1.6/purify.min.js","sha512-jB0TkTBeQC9ZSkBqDhdmfTv1qdfbWpGE72yJ/01Srq6hEzZIz2xkz1e57p9ai7IeHMwEG7HpzG6NdptChif5Pg=="),await C("https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js","sha512-tjg8I2d6Fi0OBGz1csmr7RfI4uupYaCfL/RqhVRTS42RMGwfBsjwBGmhzhI+e2dPmyew8cFkoxnVkGvADDLvbg=="),await I("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css","sha512-rO+olRTkcf304DQBxSWxln8JXCzTHlKnIdnMUwYvQa9/Jd4cQaNkItIUj6Z4nvW1dqK0SKXLbn9h4KwZTNtAyw=="),await C("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js","sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ=="),await async function(){await Promise.all([x("https://cdnjs.cloudflare.com/ajax/libs/readability/0.4.4/Readability.min.js","sha384-YqVytsOEvlLnJ+cNHmbexthfaZ482cPdQ+GQuIZngy2l0P+HIKE7wpmcUC6Ni5iw"),x("https://cdnjs.cloudflare.com/ajax/libs/turndown/7.1.2/turndown.min.js","sha384-m6AyXEhyWRg2s2wrkDV64LGkaManYgMSAjn2U+zymzSJ42WthRSjCu1AqZJhoQV0")]),b=window.Readability,h=window.TurndownService,console.log("📚 Scraper libraries loaded")}()}(),function(){const n=document.createElement("style");n.id="ai-chat-widget-styles",n.textContent="\n #ai-widget-root {\n --bg-panel: rgba(9, 9, 11, 0.92);\n --bg-input: rgba(24, 24, 27, 0.6);\n --border-color: rgba(39, 39, 42, 0.6);\n --text-primary: #fafafa;\n --text-secondary: #a1a1aa;\n --user-bubble-bg: #27272a;\n --bot-bubble-bg: rgba(24, 24, 27, 0.6);\n --shadow-color: rgba(0, 0, 0, 0.4);\n --fab-bg: rgba(24, 24, 27, 0.8);\n --accent: #a855f7;\n --send-bg: #a855f7;\n --send-color: #fff;\n --border-hover: rgba(168, 85, 247, 0.3);\n }\n\n #ai-widget-root[data-theme=\"light\"] {\n --bg-panel: rgba(245, 245, 245, 0.92);\n --bg-input: rgba(0, 0, 0, 0.02);\n --border-color: rgba(0, 0, 0, 0.08);\n --text-primary: #111;\n --text-secondary: #555;\n --user-bubble-bg: #e0e0e0;\n --bot-bubble-bg: rgba(255, 255, 255, 0.5);\n --shadow-color: rgba(0, 0, 0, 0.05);\n --fab-bg: rgba(255, 255, 255, 0.6);\n --accent: #888;\n --send-bg: #222;\n --send-color: #fff;\n --border-hover: rgba(0, 0, 0, 0.15);\n }\n\n @keyframes slideUpFade {\n 0% { opacity: 0; transform: translateY(30px) scale(0.95); }\n 100% { opacity: 1; transform: translateY(0) scale(1); }\n }\n @keyframes pulseDot {\n 0%, 100% { transform: scale(0.8); opacity: 0.4; }\n 50% { transform: scale(1.2); opacity: 1; }\n }\n @keyframes typing {\n 0%, 80%, 100% { opacity: 0.3; transform: translateY(2px); }\n 40% { opacity: 1; transform: translateY(-2px); }\n }\n @keyframes previewPop {\n 0% { opacity: 0; transform: scale(0.8) translateY(10px); }\n 100% { opacity: 1; transform: scale(1) translateY(0); }\n }\n @keyframes fabPulse {\n 0% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0.1); }\n 70% { box-shadow: 0 0 0 16px rgba(168, 85, 247, 0); }\n 100% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0); }\n }\n\n #ai-widget-root {\n all: initial;\n font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 999999;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n pointer-events: none;\n color: var(--text-primary);\n }\n #ai-widget-root * { box-sizing: border-box; pointer-events: auto; }\n\n #ai-widget-root .fas,\n #ai-widget-root .far,\n #ai-widget-root .fab {\n font-family: 'Font Awesome 6 Free', 'Font Awesome 6 Brands' !important;\n font-weight: 900 !important;\n font-style: normal;\n font-variant: normal;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n }\n #ai-widget-root .far { font-weight: 400 !important; }\n #ai-widget-root .fab {\n font-family: 'Font Awesome 6 Brands' !important;\n font-weight: 400 !important;\n }\n\n .ai-fab {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: var(--fab-bg);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border: 1px solid var(--border-color);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--text-primary);\n transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n user-select: none;\n box-shadow: 0 4px 24px var(--shadow-color);\n position: relative;\n z-index: 10;\n will-change: transform, opacity;\n animation: fabPulse 3s infinite;\n }\n .ai-fab:hover {\n transform: scale(1.06);\n box-shadow: 0 6px 32px var(--shadow-color);\n border-color: var(--accent);\n }\n .ai-fab .bot-icon i {\n color: #fafafa !important;\n font-size: 26px !important;\n filter: none;\n }\n .ai-panel.open ~ .ai-fab {\n opacity: 0;\n transform: scale(0.8);\n pointer-events: none;\n animation: none;\n }\n\n .ai-panel {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 420px;\n max-width: calc(100vw - 48px);\n height: 620px;\n max-height: calc(100vh - 48px);\n background: var(--bg-panel);\n backdrop-filter: blur(24px);\n -webkit-backdrop-filter: blur(24px);\n border-radius: 28px;\n box-shadow: 0 16px 64px var(--shadow-color), 0 0 0 1px var(--border-color);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n opacity: 0;\n visibility: hidden;\n transform: translateY(20px) scale(0.96);\n transition: all 0.35s cubic-bezier(0.16, 1, 0.3, 1);\n border: 1px solid var(--border-color);\n }\n .ai-panel.open {\n opacity: 1;\n visibility: visible;\n transform: translateY(0) scale(1);\n }\n\n .ai-header {\n padding: 20px 24px;\n border-bottom: 1px solid var(--border-color);\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n }\n .ai-header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .ai-header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n color: var(--text-primary);\n font-weight: 600;\n font-size: 16px;\n letter-spacing: -0.3px;\n }\n .status-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #a855f7;\n animation: pulseDot 2s infinite;\n flex-shrink: 0;\n }\n .ai-theme-toggle,\n .ai-close-btn,\n .ai-clear-btn {\n background: transparent;\n border: 1px solid var(--border-color);\n color: var(--text-secondary);\n width: 32px;\n height: 32px;\n border-radius: 50%;\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .ai-theme-toggle:hover,\n .ai-close-btn:hover,\n .ai-clear-btn:hover {\n background: var(--border-color);\n color: var(--text-primary);\n }\n .ai-theme-toggle:hover {\n transform: rotate(180deg) !important;\n }\n .ai-close-btn:hover {\n transform: rotate(90deg);\n }\n\n .ai-messages {\n flex: 1;\n padding: 24px 24px 16px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 20px;\n scroll-behavior: smooth;\n }\n .ai-messages::-webkit-scrollbar { width: 4px; }\n .ai-messages::-webkit-scrollbar-track { background: transparent; }\n .ai-messages::-webkit-scrollbar-thumb {\n background: var(--border-color);\n border-radius: 10px;\n }\n\n .msg {\n max-width: 85%;\n font-size: 14.5px;\n line-height: 1.7;\n word-break: break-word;\n animation: slideUpFade 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n color: var(--text-primary);\n padding: 12px 18px;\n border-radius: 18px;\n position: relative;\n box-shadow: 0 1px 4px var(--shadow-color);\n }\n .msg.user {\n align-self: flex-end;\n background: var(--user-bubble-bg);\n border: 1px solid var(--border-color);\n border-bottom-right-radius: 4px;\n }\n .msg.bot {\n align-self: flex-start;\n background: var(--bot-bubble-bg);\n border: 1px solid var(--border-color);\n border-bottom-left-radius: 4px;\n max-width: 95%;\n padding-bottom: 32px;\n }\n\n .msg.user::after {\n content: '';\n position: absolute;\n bottom: 0;\n right: -6px;\n width: 12px;\n height: 12px;\n background: var(--user-bubble-bg);\n border-radius: 0 0 12px 0;\n clip-path: polygon(0 0, 100% 0, 100% 100%);\n }\n .msg.bot::before {\n content: '';\n position: absolute;\n bottom: 0;\n left: -6px;\n width: 12px;\n height: 12px;\n background: var(--bot-bubble-bg);\n border-radius: 0 0 0 12px;\n clip-path: polygon(0 0, 100% 100%, 100% 0);\n }\n\n .msg.bot p { margin: 0 0 12px 0; }\n .msg.bot p:last-child { margin-bottom: 0; }\n .msg.bot code {\n background: rgba(39, 39, 42, 0.6);\n padding: 2px 8px;\n border-radius: 6px;\n font-family: ui-monospace, monospace;\n font-size: 0.9em;\n border: 1px solid rgba(39, 39, 42, 0.4);\n color: #e4e4e7;\n }\n .msg.bot pre {\n background: rgba(9, 9, 11, 0.4);\n padding: 16px;\n border-radius: 14px;\n overflow-x: auto;\n margin: 12px 0;\n border: 1px solid rgba(39, 39, 42, 0.4);\n }\n .msg.bot pre code { background: transparent; padding: 0; border: none; }\n .msg.bot ul, .msg.bot ol { margin: 8px 0 12px 20px; padding-left: 0; }\n .msg.bot li { margin-bottom: 6px; }\n .msg.bot a { color: #a855f7; text-decoration: none; border-bottom: 1px dotted rgba(168, 85, 247, 0.2); }\n .msg .image-preview {\n max-width: 200px;\n border-radius: 14px;\n margin-top: 8px;\n border: 1px solid var(--border-color);\n }\n\n .msg-regen-btn,\n .msg-retry-btn {\n background: transparent;\n border: 1px solid var(--border-color);\n color: var(--text-secondary);\n padding: 4px 10px;\n border-radius: 20px;\n font-size: 12px;\n cursor: pointer;\n margin-top: 8px;\n transition: all 0.2s ease;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n }\n .msg-regen-btn:hover,\n .msg-retry-btn:hover {\n background: var(--border-color);\n color: var(--text-primary);\n border-color: var(--accent);\n }\n .msg.bot .msg-regen-btn {\n position: absolute;\n bottom: 8px;\n right: 8px;\n opacity: 0.6;\n font-size: 14px;\n padding: 4px 6px;\n border-radius: 50%;\n width: 30px;\n height: 30px;\n justify-content: center;\n background: var(--bg-panel);\n margin-top: 0;\n border: 1px solid var(--border-color);\n }\n .msg.bot .msg-regen-btn:hover {\n opacity: 1;\n }\n .msg-retry-btn {\n background: rgba(239, 68, 68, 0.1);\n border-color: rgba(239, 68, 68, 0.3);\n color: #ef4444;\n margin-left: 4px;\n }\n .msg-retry-btn:hover {\n background: rgba(239, 68, 68, 0.2);\n border-color: #ef4444;\n color: #ef4444;\n }\n\n .ai-input-area {\n padding: 12px 20px 20px;\n background: transparent;\n flex-shrink: 0;\n border-top: 1px solid var(--border-color);\n }\n .ai-input-container {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n background: var(--bg-input);\n border: 1px solid var(--border-color);\n border-radius: 20px;\n padding: 4px 4px 4px 16px;\n transition: all 0.25s ease;\n min-height: 48px;\n }\n .ai-input-container:focus-within {\n border-color: var(--accent);\n box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.08);\n }\n .ai-input-container textarea {\n flex: 1;\n background: transparent;\n border: none;\n color: var(--text-primary);\n font-size: 14px;\n outline: none;\n font-family: inherit;\n padding: 10px 0;\n resize: none;\n max-height: 150px;\n line-height: 1.6;\n min-height: 28px;\n scrollbar-width: none;\n }\n .ai-input-container textarea::placeholder {\n color: var(--text-secondary);\n font-weight: 400;\n }\n\n .icon-btn {\n background: transparent;\n border: none;\n color: var(--text-secondary);\n width: 38px;\n height: 38px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n align-self: flex-end;\n margin-bottom: 2px;\n }\n .icon-btn:hover {\n color: var(--text-primary);\n background: var(--border-color);\n transform: scale(1.05);\n }\n .icon-btn:active { transform: scale(0.92); }\n\n .send-btn {\n background: var(--send-bg);\n color: var(--send-color);\n width: 38px;\n height: 38px;\n align-self: flex-end;\n margin-bottom: 2px;\n box-shadow: 0 2px 8px var(--shadow-color);\n transition: all 0.25s ease;\n border: none;\n }\n .send-btn:hover {\n transform: scale(1.06);\n box-shadow: 0 4px 12px var(--shadow-color);\n }\n .send-btn:active { transform: scale(0.92); }\n .send-btn:disabled {\n background: rgba(39, 39, 42, 0.6);\n color: var(--text-secondary);\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n }\n\n .ai-input-footer {\n display: flex;\n justify-content: flex-end;\n padding: 4px 6px 0;\n min-height: 20px;\n }\n .ai-char-count {\n font-size: 11px;\n color: var(--text-secondary);\n font-weight: 500;\n transition: color 0.2s;\n opacity: 0.4;\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n }\n\n #aiPreviewContainer {\n margin-bottom: 8px;\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n }\n .image-preview-pill {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n background: rgba(24, 24, 27, 0.8);\n border: 1px solid var(--border-color);\n border-radius: 14px;\n padding: 6px 12px 6px 6px;\n animation: previewPop 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n box-shadow: 0 2px 12px var(--shadow-color);\n transition: all 0.2s;\n max-width: 100%;\n }\n .image-preview-pill:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px var(--shadow-color);\n }\n .image-preview-pill .preview-thumb {\n width: 32px;\n height: 32px;\n border-radius: 10px;\n object-fit: cover;\n border: 1px solid var(--border-color);\n }\n .image-preview-pill .file-name {\n font-size: 12px;\n color: var(--text-primary);\n max-width: 150px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n }\n .image-preview-pill .file-size {\n font-size: 10px;\n color: var(--text-secondary);\n opacity: 0.6;\n }\n .image-preview-pill .remove-file {\n background: rgba(39, 39, 42, 0.6);\n border: none;\n color: var(--text-secondary);\n cursor: pointer;\n font-size: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 4px;\n border-radius: 50%;\n transition: all 0.2s;\n margin-left: 2px;\n width: 26px;\n height: 26px;\n }\n .image-preview-pill .remove-file:hover {\n color: #ef4444;\n background: rgba(239,68,68,0.12);\n transform: scale(1.1);\n }\n\n .typing-indicator {\n display: flex;\n gap: 6px;\n padding: 12px 0;\n align-self: flex-start;\n background: rgba(24, 24, 27, 0.6);\n padding: 10px 16px;\n border-radius: 18px;\n border: 1px solid var(--border-color);\n }\n .typing-indicator span {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #a855f7;\n animation: typing 1.4s infinite;\n }\n .typing-indicator span:nth-child(2) { animation-delay: 0.2s; }\n .typing-indicator span:nth-child(3) { animation-delay: 0.4s; }\n\n @media (max-width: 480px) {\n .ai-panel {\n width: calc(100vw - 32px);\n right: 16px;\n height: 80vh;\n max-height: calc(100vh - 48px);\n border-radius: 20px;\n }\n .ai-fab {\n width: 52px;\n height: 52px;\n }\n .ai-fab .bot-icon { font-size: 22px; }\n .ai-input-area {\n padding: 8px 14px 14px;\n }\n .ai-input-container {\n border-radius: 16px;\n padding: 2px 2px 2px 12px;\n min-height: 42px;\n }\n .ai-input-container textarea { font-size: 13px; padding: 8px 0; }\n .icon-btn { width: 32px; height: 32px; }\n .send-btn { width: 32px; height: 32px; }\n .image-preview-pill .file-name { max-width: 100px; }\n .msg.bot {\n padding-bottom: 28px;\n }\n }\n ",document.head.appendChild(n)}(),function(){const t=window.__NEXUS_CONFIG?.BOT_NAME||n.BOT_NAME,o=a(window.__NEXUS_CONFIG?.GREETING||n.GREETING),r=document.createElement("div");r.id="ai-widget-root",r.innerHTML=`\n <div class="ai-panel" id="aiPanel">\n <div class="ai-header">\n <div class="ai-header-title">\n <span class="status-dot"></span>\n ${t}\n </div>\n <div class="ai-header-actions">\n <button class="ai-theme-toggle" id="aiThemeToggle" aria-label="Toggle theme">\n <i class="fas fa-moon"></i>\n </button>\n <button class="ai-clear-btn" id="aiClearBtn" aria-label="Clear chat">\n <i class="fas fa-trash"></i>\n </button>\n <button class="ai-close-btn" id="aiCloseBtn" aria-label="Close chat">\n <i class="fas fa-xmark"></i>\n </button>\n </div>\n </div>\n <div class="ai-messages" id="aiMessages">\n <div class="msg bot">\n ${o}\n </div>\n </div>\n <div class="ai-input-area" id="aiInputArea">\n <div id="aiPreviewContainer"></div>\n <div class="ai-input-container">\n <button class="icon-btn" id="aiAttachBtn" aria-label="Attach image or file">\n <i class="fas fa-paperclip"></i>\n </button>\n <textarea \n id="aiInput" \n placeholder="Message..." \n rows="1"\n autocomplete="off"\n spellcheck="true"\n ></textarea>\n <button class="icon-btn send-btn" id="aiSendBtn">\n <i class="fas fa-arrow-up"></i>\n </button>\n </div>\n <div class="ai-input-footer">\n <span class="ai-char-count" id="aiCharCount">0</span>\n </div>\n </div>\n </div>\n <button class="ai-fab" id="aiFab" aria-label="Open AI Chat">\n <span class="bot-icon">\n <i class="fas fa-robot" style="color: #ffffff !important; font-size: 22px;"></i>\n </span>\n </button>\n `,document.body.appendChild(r);const i=e("aiInput");i&&i.addEventListener("input",()=>{!function(n){n.style.height="auto",n.style.height=Math.min(n.scrollHeight,150)+"px"}(i),function(n){const t=e("aiCharCount");if(t){const e=n.value.length;t.textContent=e>0?`${e}`:"0",t.style.color=e>500?"#ef4444":"#a0a0a0"}}(i)})}();const i=document.getElementById("ai-widget-root");i&&(i.dataset.theme=t.THEME||"dark");const s=document.getElementById("aiThemeToggle");if(s){const n="dark"===t.THEME;s.innerHTML=n?'<i class="fas fa-moon"></i>':'<i class="fas fa-sun"></i>',s.title=n?"Switch to Light":"Switch to Dark",s.addEventListener("click",T)}const g=e("aiPanel"),y=e("aiMessages"),v=e("aiFab"),S=e("aiCloseBtn"),O=e("aiSendBtn"),L=e("aiInput"),M=e("aiAttachBtn"),A=e("aiPreviewContainer"),_=e("aiClearBtn");_&&_.addEventListener("click",()=>{if(confirm("Clear all chat messages?")){y.innerHTML="";const e=function(n){if(!n)return"";try{if("undefined"!=typeof marked&&marked.parse){const e=marked.parse(n,{breaks:!0,gfm:!0});return"undefined"!=typeof DOMPurify&&DOMPurify.sanitize?DOMPurify.sanitize(e):e}}catch(n){console.warn("Markdown parse failed:",n)}return n.replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br>")}(window.__NEXUS_CONFIG?.GREETING||n.GREETING),a=document.createElement("div");a.className="msg bot",a.innerHTML=e,y.appendChild(a),c.conversationHistory=[{role:"system",content:t.SYSTEM_PROMPT}],function(){try{localStorage.removeItem("nexus-chat-history")}catch{}}(),d({lastUserMessage:null,lastBotMessageEl:null,lastErrorMessageEl:null})}}),function(n){let e=window.location.href;new MutationObserver(()=>{window.location.href!==e&&(e=window.location.href,console.log("🔄 Page navigation detected"),n())}).observe(document.body,{childList:!0,subtree:!1}),window.addEventListener("popstate",()=>{setTimeout(()=>{window.location.href!==e&&(e=window.location.href,n())},100)})}(()=>{console.log("🔄 Page changed, refreshing context..."),async function(){console.log("🔄 Forcing page context refresh...");const n=E(w());await f(n),console.log("✅ Page context refreshed")}(),r(y,"🔄 Page context updated!","bot")});const P=document.createElement("input");P.type="file";const R=n.ALLOWED_FILE_TYPES||["image/*"];function N(){c.abortController&&(c.abortController.abort(),d({abortController:null})),d({isOpen:o(g,!1)})}P.accept=R.join(","),P.style.display="none",P.id="aiFileInput",document.body.appendChild(P),M?.addEventListener("click",()=>P.click()),P.addEventListener("change",n=>{const e=n.target.files?.[0];if(!e)return;if(!R.some(n=>{if(n.endsWith("/*")){const t=n.slice(0,-2);return e.type.startsWith(t)}return e.type===n||e.name.endsWith(n.slice(1))}))return void alert("Please select a valid file type.");const t=new FileReader;t.onload=n=>{const t={dataUrl:n.target.result,name:e.name,type:e.type,size:e.size};d({attachedFile:t}),l(A,t);const a=document.getElementById("aiRemoveFile");a&&a.addEventListener("click",()=>{d({attachedFile:null}),l(A,null),L?.focus()}),L?.focus()},t.readAsDataURL(e),n.target.value=""}),v?.addEventListener("click",()=>{d({isOpen:o(g,!0)})}),S?.addEventListener("click",N),document.addEventListener("click",n=>{const e=document.getElementById("ai-widget-root");e&&c.isOpen&&!e.contains(n.target)&&N()});const B=()=>{const n=L?.value.trim();if(!n&&!c.attachedFile)return;if(c.isProcessing)return;c.attachedFile;const e=c.attachedFile?.dataUrl||null;d({attachedFile:null,lastUserMessage:{text:n,image:e}}),L.value="",L.style.height="auto",l(A,null),k(y,n,e)};O?.addEventListener("click",B),L?.addEventListener("keydown",n=>{"Enter"!==n.key||n.shiftKey||(n.preventDefault(),B())}),document.addEventListener("regenerate-request",n=>{const{messageEl:e}=n.detail;if(!e)return;if(c.isProcessing)return;const t=c.conversationHistory,a=t.length-1;if(a<0||"assistant"!==t[a].role)return;const o=a-1;if(o<0||"user"!==t[o].role)return;const r=t[o].content;t.pop(),e.remove(),c.lastBotMessageEl===e&&d({lastBotMessageEl:null}),k(y,r,null,{skipUserAdd:!0})});const j=function(){try{const n=localStorage.getItem("nexus-chat-history");return n?JSON.parse(n):null}catch{return null}}();j&&j.length>0&&(c.conversationHistory=[{role:"system",content:t.SYSTEM_PROMPT}],j.forEach(n=>{if("user"===n.role)r(y,n.content,"user");else if("assistant"===n.role){const e=r(y,n.content,"bot",null,{withRegenerate:!0});e&&n===j[j.length-1]&&d({lastBotMessageEl:e})}c.conversationHistory.push(n)}));const H=await async function(){try{const n=(await m()).transaction(u,"readonly").objectStore(u);return new Promise(e=>{const t=n.count();t.onsuccess=()=>{e({totalEntries:t.result,database:p,version:1})},t.onerror=()=>e(null)})}catch{return null}}();console.log("📊 Cache Stats:",H||"No cache yet"),console.log("✨ Nexus AI v2.0 initialized with theme:",t.THEME)}c.conversationHistory=[{role:"system",content:n.SYSTEM_PROMPT}],"loading"===document.readyState?document.addEventListener("DOMContentLoaded",O):O()})();
|