cevvo-widget 1.0.7 → 1.1.0

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.
Files changed (2) hide show
  1. package/dist/widget.js +88 -45
  2. package/package.json +1 -1
package/dist/widget.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(){"use strict";(function(){const p="https://prod-backend-api.cevvo.ai/api/v1",b={projectId:"",apiKey:"",apiUrl:p,projectName:"AI Assistant",projectColor:"#2563eb",buttonText:"Ask AI",buttonBgColor:"#2563eb",buttonTextColor:"#ffffff",buttonPosition:"bottom-right",buttonOffsetX:"20px",buttonOffsetY:"20px",modalTitle:"AI Assistant",modalSubtitle:"Ask me anything",modalPlaceholder:"Ask a question...",modalExampleQuestions:[],modalWidth:"420px",modalHeight:"600px",mode:"chat",theme:"light",welcomeMessage:"Hi! How can I help you?"},i={cevvoLogo:`<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 32 32">
1
+ (function(){"use strict";(function(){const p="https://prod-backend-api.cevvo.ai/api/v1",b={projectId:"",apiKey:"",apiUrl:p,projectName:"AI Assistant",projectColor:"#2563eb",buttonText:"Ask AI",buttonBgColor:"#2563eb",buttonTextColor:"#ffffff",buttonPosition:"bottom-right",buttonOffsetX:"20px",buttonOffsetY:"20px",modalTitle:"AI Assistant",modalSubtitle:"Ask me anything",modalPlaceholder:"Ask a question...",modalExampleQuestions:[],modalWidth:"420px",modalHeight:"600px",mode:"chat",theme:"light",welcomeMessage:"Hi! How can I help you?",disclaimer:"AI responses may be inaccurate or incomplete. Please verify important information from original sources."},n={cevvoLogo:`<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 32 32">
2
2
  <ellipse cx="13" cy="16" rx="8" ry="10" fill="#21244A" transform="rotate(-15 13 16)"/>
3
3
  <ellipse cx="19" cy="16" rx="8" ry="10" fill="#F69F06" transform="rotate(15 19 16)" opacity="0.85"/>
4
4
  </svg>`,close:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 256 256" fill="currentColor">
@@ -308,18 +308,41 @@
308
308
  border-bottom-right-radius: 4px;
309
309
  }
310
310
 
311
- .cevvo-bubble code {
311
+ .cevvo-bubble .cevvo-inline-code {
312
312
  background: rgba(0,0,0,0.08);
313
313
  padding: 2px 6px;
314
314
  border-radius: 4px;
315
- font-family: 'SF Mono', Monaco, monospace;
316
- font-size: 13px;
315
+ font-family: 'SF Mono', 'Fira Code', Monaco, Consolas, monospace;
316
+ font-size: 12px;
317
317
  }
318
318
 
319
- .cevvo-bubble.user code {
319
+ .cevvo-bubble.user .cevvo-inline-code {
320
320
  background: rgba(255,255,255,0.15);
321
321
  }
322
322
 
323
+ .cevvo-bubble .cevvo-code-block {
324
+ background: #1a1b26;
325
+ color: #c0caf5;
326
+ border-radius: 8px;
327
+ padding: 14px 16px;
328
+ margin: 8px 0;
329
+ overflow-x: auto;
330
+ font-family: 'SF Mono', 'Fira Code', Monaco, Consolas, monospace;
331
+ font-size: 12px;
332
+ line-height: 1.6;
333
+ white-space: pre;
334
+ word-break: normal;
335
+ -webkit-overflow-scrolling: touch;
336
+ }
337
+
338
+ .cevvo-bubble .cevvo-code-block code {
339
+ background: none;
340
+ padding: 0;
341
+ border-radius: 0;
342
+ font-size: inherit;
343
+ color: inherit;
344
+ }
345
+
323
346
  /* Typing indicator */
324
347
  .cevvo-typing {
325
348
  display: flex;
@@ -465,8 +488,12 @@
465
488
  border: 1px solid #e4e4e7;
466
489
  border-radius: 10px;
467
490
  font-size: 14px;
491
+ line-height: 1.5;
468
492
  outline: none;
469
493
  background: #fff;
494
+ box-sizing: border-box;
495
+ width: 100%;
496
+ min-width: 0;
470
497
  transition: border-color 0.15s ease;
471
498
  }
472
499
 
@@ -501,6 +528,15 @@
501
528
  opacity: 0.85;
502
529
  }
503
530
 
531
+ .cevvo-disclaimer {
532
+ text-align: center;
533
+ font-size: 9px;
534
+ line-height: 1.4;
535
+ color: #a1a1aa;
536
+ margin: 0 0 8px;
537
+ padding: 0 12px;
538
+ }
539
+
504
540
  .cevvo-powered {
505
541
  text-align: center;
506
542
  font-size: 11px;
@@ -579,18 +615,22 @@
579
615
  .cevvo-modal-overlay.mode-modal .cevvo-input-wrapper {
580
616
  display: flex;
581
617
  flex-direction: column;
582
- gap: 12px;
583
- padding: 16px;
618
+ gap: 10px;
619
+ padding: 14px 16px;
584
620
  border: 1px solid #e4e4e7;
585
621
  border-radius: 14px;
586
622
  background: #fff;
623
+ box-sizing: border-box;
587
624
  }
588
625
 
589
626
  .cevvo-modal-overlay.mode-modal .cevvo-input {
590
627
  border: none;
591
- padding: 0;
628
+ padding: 4px 0;
592
629
  font-size: 15px;
630
+ line-height: 1.5;
593
631
  background: transparent;
632
+ width: 100%;
633
+ box-sizing: border-box;
594
634
  }
595
635
 
596
636
  .cevvo-modal-overlay.mode-modal .cevvo-input:focus {
@@ -819,56 +859,58 @@
819
859
  border-color: #38383a;
820
860
  color: #e5e5ea;
821
861
  }
822
- `;class h{constructor(e={}){this.config={...b,...e},this.isOpen=!1,this.messages=[],this.threadId=null,this.isLoading=!1;const o=()=>{this.injectStyles(),this.createElements(),this.bindEvents()};document.body?o():document.addEventListener("DOMContentLoaded",o)}injectStyles(){if(document.getElementById("cevvo-widget-styles"))return;const e=document.createElement("style");e.id="cevvo-widget-styles",e.textContent=f,document.head.appendChild(e)}resolveTheme(){return this.config.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":this.config.theme||"light"}createElements(){this.container=document.createElement("div");const e=this.resolveTheme()==="dark"?"cevvo-dark":"";this.container.className=`cevvo-widget ${e}`.trim(),this.container.style.setProperty("--cevvo-accent",this.config.projectColor),this.button=document.createElement("button"),this.button.className=`cevvo-widget-btn ${this.config.buttonPosition}`,this.button.style.background=this.config.buttonBgColor,this.button.style.color=this.config.buttonTextColor,this.button.innerHTML=`${i.cevvoLogo}<span>${this.config.buttonText}</span>`,this.overlay=document.createElement("div"),this.overlay.className=`cevvo-modal-overlay ${this.config.mode==="modal"?"mode-modal":""}`,this.overlay.innerHTML=this.config.mode==="modal"?this.renderModalMode():this.renderModal(),this.container.appendChild(this.button),this.container.appendChild(this.overlay),document.body.appendChild(this.container),this.modal=this.overlay.querySelector(".cevvo-modal"),this.messagesContainer=this.overlay.querySelector(".cevvo-modal-body"),this.input=this.overlay.querySelector(".cevvo-input"),this.form=this.overlay.querySelector(".cevvo-input-form"),this.clearBtn=this.overlay.querySelector(".cevvo-clear-btn"),this.closeBtn=this.overlay.querySelector(".cevvo-close-btn")}renderModal(){const e=this.config.modalExampleQuestions.map(o=>`<button class="cevvo-example-btn">${this.escapeHtml(o)}</button>`).join("");return`
862
+ `;class h{constructor(o={}){this.config={...b,...o},this.isOpen=!1,this.messages=[],this.threadId=null,this.isLoading=!1;const e=()=>{this.injectStyles(),this.createElements(),this.bindEvents()};document.body?e():document.addEventListener("DOMContentLoaded",e)}injectStyles(){if(document.getElementById("cevvo-widget-styles"))return;const o=document.createElement("style");o.id="cevvo-widget-styles",o.textContent=f,document.head.appendChild(o)}resolveTheme(){return this.config.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":this.config.theme||"light"}createElements(){this.container=document.createElement("div");const o=this.resolveTheme()==="dark"?"cevvo-dark":"";this.container.className=`cevvo-widget ${o}`.trim(),this.container.style.setProperty("--cevvo-accent",this.config.projectColor),this.button=document.createElement("button"),this.button.className=`cevvo-widget-btn ${this.config.buttonPosition}`,this.button.style.background=this.config.buttonBgColor,this.button.style.color=this.config.buttonTextColor,this.button.innerHTML=`${n.cevvoLogo}<span>${this.config.buttonText}</span>`,this.overlay=document.createElement("div"),this.overlay.className=`cevvo-modal-overlay ${this.config.mode==="modal"?"mode-modal":""}`,this.overlay.innerHTML=this.config.mode==="modal"?this.renderModalMode():this.renderModal(),this.container.appendChild(this.button),this.container.appendChild(this.overlay),document.body.appendChild(this.container),this.modal=this.overlay.querySelector(".cevvo-modal"),this.messagesContainer=this.overlay.querySelector(".cevvo-modal-body"),this.input=this.overlay.querySelector(".cevvo-input"),this.form=this.overlay.querySelector(".cevvo-input-form"),this.clearBtn=this.overlay.querySelector(".cevvo-clear-btn"),this.closeBtn=this.overlay.querySelector(".cevvo-close-btn")}renderModal(){const o=this.config.modalExampleQuestions.map(e=>`<button class="cevvo-example-btn">${this.escapeHtml(e)}</button>`).join("");return`
823
863
  <div class="cevvo-modal">
824
864
  <div class="cevvo-modal-header">
825
865
  <div class="cevvo-header-info">
826
- <div class="cevvo-header-logo">${i.cevvoLogo}</div>
866
+ <div class="cevvo-header-logo">${n.cevvoLogo}</div>
827
867
  <div class="cevvo-header-text">
828
868
  <h2>${this.escapeHtml(this.config.modalTitle)}</h2>
829
869
  <p>${this.escapeHtml(this.config.modalSubtitle)}</p>
830
870
  </div>
831
871
  </div>
832
872
  <div class="cevvo-header-actions">
833
- <button class="cevvo-clear-btn" title="Clear chat" style="display:none;">${i.trash}</button>
834
- <button class="cevvo-close-btn" title="Close">${i.close}</button>
873
+ <button class="cevvo-clear-btn" title="Clear chat" style="display:none;">${n.trash}</button>
874
+ <button class="cevvo-close-btn" title="Close">${n.close}</button>
835
875
  </div>
836
876
  </div>
837
877
  <div class="cevvo-modal-body">
838
878
  <div class="cevvo-empty-state">
839
- <div class="cevvo-empty-icon">${i.sparkle}</div>
879
+ <div class="cevvo-empty-icon">${n.sparkle}</div>
840
880
  <h3>${this.escapeHtml(this.config.welcomeMessage)}</h3>
841
- ${e?`<div class="cevvo-example-questions">${e}</div>`:""}
881
+ ${o?`<div class="cevvo-example-questions">${o}</div>`:""}
842
882
  </div>
843
883
  </div>
844
884
  <div class="cevvo-modal-footer">
885
+ ${this.config.disclaimer?`<p class="cevvo-disclaimer">${this.escapeHtml(this.config.disclaimer)}</p>`:""}
845
886
  <form class="cevvo-input-form">
846
887
  <input type="text" class="cevvo-input" placeholder="${this.escapeHtml(this.config.modalPlaceholder)}" />
847
- <button type="submit" class="cevvo-send-btn" disabled>${i.send}</button>
888
+ <button type="submit" class="cevvo-send-btn" disabled>${n.send}</button>
848
889
  </form>
849
890
  <p class="cevvo-powered">Powered by <a href="https://cevvo.ai" target="_blank" rel="noopener">Cevvo</a></p>
850
891
  </div>
851
892
  </div>
852
- `}renderModalMode(){const e=this.config.modalDescription||'This is a <a href="#">Cevvo-powered</a> AI assistant with access to all documentation, FAQs, API specs and tutorials. This is an example of the <a href="#">website widget</a> integration.';return`
893
+ `}renderModalMode(){const o=this.config.modalDescription||this.config.modalSubtitle||"Ask me anything about the documentation.";return`
853
894
  <div class="cevvo-modal">
854
895
  <div class="cevvo-modal-header">
855
896
  <div class="cevvo-header-info">
856
- <div class="cevvo-header-logo">${i.cevvoLogo}</div>
897
+ <div class="cevvo-header-logo">${n.cevvoLogo}</div>
857
898
  <div class="cevvo-header-text">
858
899
  <h2>${this.escapeHtml(this.config.modalTitle)}</h2>
859
900
  </div>
860
901
  </div>
861
902
  <div class="cevvo-header-actions">
862
- <button class="cevvo-clear-btn" title="Clear chat" style="display:none;">${i.trash}</button>
863
- <button class="cevvo-close-btn" title="Close">${i.close}</button>
903
+ <button class="cevvo-clear-btn" title="Clear chat" style="display:none;">${n.trash}</button>
904
+ <button class="cevvo-close-btn" title="Close">${n.close}</button>
864
905
  </div>
865
906
  </div>
866
907
  <div class="cevvo-modal-description" style="padding: 0 24px;">
867
- ${e}
908
+ ${o}
868
909
  </div>
869
910
  <div class="cevvo-modal-body">
870
911
  </div>
871
912
  <div class="cevvo-modal-footer">
913
+ ${this.config.disclaimer?`<p class="cevvo-disclaimer">${this.escapeHtml(this.config.disclaimer)}</p>`:""}
872
914
  <div class="cevvo-input-wrapper">
873
915
  <form class="cevvo-input-form" style="gap: 0;">
874
916
  <input type="text" class="cevvo-input" placeholder="${this.escapeHtml(this.config.modalPlaceholder)}" />
@@ -879,61 +921,62 @@
879
921
  For harder questions. Searches longer across all sources. Takes up to ~1 minute.
880
922
  </div>
881
923
  <button type="button" class="cevvo-deep-thinking-btn">
882
- ${i.brain}
924
+ ${n.brain}
883
925
  <span>Deep thinking</span>
884
926
  </button>
885
927
  </div>
886
- <button type="submit" class="cevvo-send-btn" disabled>${i.arrowUp}</button>
928
+ <button type="submit" class="cevvo-send-btn" disabled>${n.arrowUp}</button>
887
929
  </div>
888
930
  </div>
889
931
  <div class="cevvo-powered">
890
932
  <div class="cevvo-powered-left">
891
933
  <span>Powered by</span>
892
- ${i.cevvoLogo}
934
+ ${n.cevvoLogo}
893
935
  <a href="https://cevvo.ai" target="_blank" rel="noopener">cevvo.ai</a>
894
936
  </div>
895
937
  </div>
896
938
  </div>
897
939
  </div>
898
- `}bindEvents(){this.button.addEventListener("click",()=>this.toggle()),this.overlay.addEventListener("click",o=>{o.target===this.overlay&&this.close()}),this.closeBtn.addEventListener("click",()=>this.close()),this.clearBtn.addEventListener("click",()=>this.clearMessages()),this.form.addEventListener("submit",o=>{o.preventDefault(),this.sendMessage()}),this.overlay.querySelector(".cevvo-send-btn").addEventListener("click",o=>{o.preventDefault(),this.sendMessage()}),this.input.addEventListener("input",()=>{const o=this.overlay.querySelector(".cevvo-send-btn");o.disabled=!this.input.value.trim()||this.isLoading}),this.input.addEventListener("keydown",o=>{o.key==="Enter"&&!o.shiftKey&&(o.preventDefault(),this.sendMessage())}),this.overlay.addEventListener("click",o=>{o.target.classList.contains("cevvo-example-btn")&&(this.input.value=o.target.textContent,this.sendMessage())}),this.messagesContainer.addEventListener("click",o=>{const a=o.target.closest("button");if(!a)return;const s=a.closest(".cevvo-actions");if(!s)return;const n=s.dataset.messageId,c=a.closest(".cevvo-message"),l=c==null?void 0:c.dataset.msgId,r=this.messages.find(d=>d.id===l);if(a.classList.contains("cevvo-copy-btn")&&(r!=null&&r.content)&&(navigator.clipboard.writeText(r.content),a.innerHTML=i.check,setTimeout(()=>{a.innerHTML=i.copy},2e3)),a.classList.contains("cevvo-thumbs-up")&&n){const d=(r==null?void 0:r.feedback)==="positive"?null:"positive";r&&(r.feedback=d),this.submitFeedback(parseInt(n),5),this.renderMessages()}if(a.classList.contains("cevvo-thumbs-down")&&n){const d=(r==null?void 0:r.feedback)==="negative"?null:"negative";r&&(r.feedback=d),this.submitFeedback(parseInt(n),1),this.renderMessages()}}),document.addEventListener("keydown",o=>{(o.metaKey||o.ctrlKey)&&o.key==="k"&&(o.preventDefault(),this.toggle()),o.key==="Escape"&&this.isOpen&&this.close()})}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.overlay.classList.add("is-open"),this.button.style.display="none",setTimeout(()=>this.input.focus(),100)}close(){this.isOpen=!1,this.overlay.classList.remove("is-open"),this.button.style.display="flex"}updateModalState(){this.config.mode==="modal"&&(this.messages.length>0?this.overlay.classList.add("has-messages"):this.overlay.classList.remove("has-messages"))}async sendMessage(){const e=this.input.value.trim();if(!e||this.isLoading)return;if(!this.config.projectId||!this.config.apiKey){this.addMessage({role:"assistant",content:'Widget not configured. Please set Project ID and API Key, then click "Apply Changes".'});return}this.input.value="",this.overlay.querySelector(".cevvo-send-btn").disabled=!0,this.addMessage({role:"user",content:e});const o=this.addMessage({role:"assistant",content:"",isLoading:!0});this.isLoading=!0;try{const a={"Content-Type":"application/json","X-API-Key":this.config.apiKey},s=await fetch(`${this.config.apiUrl}/widget/chat/stream`,{method:"POST",headers:a,body:JSON.stringify({message:e,thread_id:this.threadId,project_id:this.config.projectId})});if(!s.ok)throw new Error("Failed to send message");const n=s.body.getReader(),c=new TextDecoder;let l="",r=[],d=null;for(;;){const{done:x,value:y}=await n.read();if(x)break;const w=c.decode(y,{stream:!0}).split(`
899
- `);for(const m of w)if(m.startsWith("data: ")){const u=m.slice(6);if(u==="[DONE]")continue;try{const v=JSON.parse(u);v.thread_id&&(this.threadId=v.thread_id),v.token&&(l+=v.token,this.updateMessage(o,{content:l,isLoading:!1})),v.sources&&(r=v.sources),v.question_answer_id&&(d=v.question_answer_id)}catch{}}}this.updateMessage(o,{content:l||"I'm sorry, I couldn't generate a response.",sources:r,messageId:d,isLoading:!1})}catch(a){console.error("Chat error:",a),this.updateMessage(o,{content:"Sorry, something went wrong. Please try again.",isLoading:!1})}finally{this.isLoading=!1}}addMessage(e){const o=Date.now().toString();return this.messages.push({id:o,...e}),this.renderMessages(),this.clearBtn.style.display="flex",this.updateModalState(),o}updateMessage(e,o){const a=this.messages.find(s=>s.id===e);a&&(Object.assign(a,o),this.renderMessages())}clearMessages(){this.messages=[],this.threadId=null,this.clearBtn.style.display="none",this.renderMessages(),this.updateModalState()}renderMessages(){if(this.messages.length===0){this.messagesContainer.innerHTML=`
940
+ `}bindEvents(){this.button.addEventListener("click",()=>this.toggle()),this.overlay.addEventListener("click",e=>{e.target===this.overlay&&this.close()}),this.closeBtn.addEventListener("click",()=>this.close()),this.clearBtn.addEventListener("click",()=>this.clearMessages()),this.form.addEventListener("submit",e=>{e.preventDefault(),this.sendMessage()}),this.overlay.querySelector(".cevvo-send-btn").addEventListener("click",e=>{e.preventDefault(),this.sendMessage()}),this.input.addEventListener("input",()=>{const e=this.overlay.querySelector(".cevvo-send-btn");e.disabled=!this.input.value.trim()||this.isLoading}),this.input.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),this.sendMessage())}),this.overlay.addEventListener("click",e=>{e.target.classList.contains("cevvo-example-btn")&&(this.input.value=e.target.textContent,this.sendMessage())}),this.messagesContainer.addEventListener("click",e=>{const t=e.target.closest("button");if(!t)return;const s=t.closest(".cevvo-actions");if(!s)return;const i=s.dataset.messageId,r=t.closest(".cevvo-message"),d=r==null?void 0:r.dataset.msgId,c=this.messages.find(l=>l.id===d);if(t.classList.contains("cevvo-copy-btn")&&(c!=null&&c.content)&&(navigator.clipboard.writeText(c.content),t.innerHTML=n.check,setTimeout(()=>{t.innerHTML=n.copy},2e3)),t.classList.contains("cevvo-thumbs-up")&&i){const l=(c==null?void 0:c.feedback)==="positive"?null:"positive";c&&(c.feedback=l),this.submitFeedback(parseInt(i),5),this.renderMessages()}if(t.classList.contains("cevvo-thumbs-down")&&i){const l=(c==null?void 0:c.feedback)==="negative"?null:"negative";c&&(c.feedback=l),this.submitFeedback(parseInt(i),1),this.renderMessages()}}),document.addEventListener("keydown",e=>{(e.metaKey||e.ctrlKey)&&e.key==="k"&&(e.preventDefault(),this.toggle()),e.key==="Escape"&&this.isOpen&&this.close()})}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.overlay.classList.add("is-open"),this.button.style.display="none",setTimeout(()=>this.input.focus(),100)}close(){this.isOpen=!1,this.overlay.classList.remove("is-open"),this.button.style.display="flex"}updateModalState(){this.config.mode==="modal"&&(this.messages.length>0?this.overlay.classList.add("has-messages"):this.overlay.classList.remove("has-messages"))}async sendMessage(){const o=this.input.value.trim();if(!o||this.isLoading)return;if(!this.config.projectId||!this.config.apiKey){this.addMessage({role:"assistant",content:'Widget not configured. Please set Project ID and API Key, then click "Apply Changes".'});return}this.input.value="",this.overlay.querySelector(".cevvo-send-btn").disabled=!0,this.addMessage({role:"user",content:o});const e=this.addMessage({role:"assistant",content:"",isLoading:!0});this.isLoading=!0;try{const t={"Content-Type":"application/json","X-API-Key":this.config.apiKey},s=await fetch(`${this.config.apiUrl}/widget/chat/stream`,{method:"POST",headers:t,body:JSON.stringify({message:o,thread_id:this.threadId,project_id:this.config.projectId})});if(!s.ok)throw new Error("Failed to send message");const i=s.body.getReader(),r=new TextDecoder;let d="",c=[],l=null;for(;;){const{done:x,value:y}=await i.read();if(x)break;const w=r.decode(y,{stream:!0}).split(`
941
+ `);for(const m of w)if(m.startsWith("data: ")){const u=m.slice(6);if(u==="[DONE]")continue;try{const v=JSON.parse(u);v.thread_id&&(this.threadId=v.thread_id),v.token&&(d+=v.token,this.updateMessage(e,{content:d,isLoading:!1})),v.sources&&(c=v.sources),v.question_answer_id&&(l=v.question_answer_id)}catch{}}}this.updateMessage(e,{content:d||"I'm sorry, I couldn't generate a response.",sources:c,messageId:l,isLoading:!1})}catch(t){console.error("Chat error:",t),this.updateMessage(e,{content:"Sorry, something went wrong. Please try again.",isLoading:!1})}finally{this.isLoading=!1}}addMessage(o){const e=Date.now().toString();return this.messages.push({id:e,...o}),this.renderMessages(),this.clearBtn.style.display="flex",this.updateModalState(),e}updateMessage(o,e){const t=this.messages.find(s=>s.id===o);t&&(Object.assign(t,e),this.renderMessages())}clearMessages(){this.messages=[],this.threadId=null,this.clearBtn.style.display="none",this.renderMessages(),this.updateModalState()}renderMessages(){if(this.messages.length===0){this.messagesContainer.innerHTML=`
900
942
  <div class="cevvo-empty-state">
901
- <div class="cevvo-empty-icon">${i.sparkle}</div>
943
+ <div class="cevvo-empty-icon">${n.sparkle}</div>
902
944
  <h3>${this.escapeHtml(this.config.welcomeMessage)}</h3>
903
945
  ${this.config.modalExampleQuestions.length?`
904
946
  <div class="cevvo-example-questions">
905
- ${this.config.modalExampleQuestions.map(e=>`<button class="cevvo-example-btn">${this.escapeHtml(e)}</button>`).join("")}
947
+ ${this.config.modalExampleQuestions.map(o=>`<button class="cevvo-example-btn">${this.escapeHtml(o)}</button>`).join("")}
906
948
  </div>
907
949
  `:""}
908
950
  </div>
909
951
  `;return}this.messagesContainer.innerHTML=`
910
952
  <div class="cevvo-messages">
911
- ${this.messages.map(e=>this.renderMessage(e)).join("")}
953
+ ${this.messages.map(o=>this.renderMessage(o)).join("")}
912
954
  </div>
913
- `,this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight}renderMessage(e){var l;const o=e.role==="assistant"?i.cevvoLogo:i.user,a=e.isLoading?'<div class="cevvo-typing"><span></span><span></span><span></span></div>':this.formatContent(e.content),s=(l=e.sources)!=null&&l.length?`
955
+ `,this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight}renderMessage(o){var d;const e=o.role==="assistant"?n.cevvoLogo:n.user,t=o.isLoading?'<div class="cevvo-typing"><span></span><span></span><span></span></div>':this.formatContent(o.content),s=(d=o.sources)!=null&&d.length?`
914
956
  <div class="cevvo-sources">
915
- <div class="cevvo-sources-header">${i.link} Sources</div>
916
- ${e.sources.map((r,d)=>`
917
- <a href="${this.escapeHtml(r.source_url||r.url||"#")}" target="_blank" rel="noopener" class="cevvo-source-link">
918
- <span class="cevvo-source-num">${d+1}</span>
919
- <span class="cevvo-source-title">${this.escapeHtml(r.title||"Source")}</span>
920
- ${i.link}
957
+ <div class="cevvo-sources-header">${n.link} Sources</div>
958
+ ${o.sources.map((c,l)=>`
959
+ <a href="${this.escapeHtml(c.source_url||c.url||"#")}" target="_blank" rel="noopener" class="cevvo-source-link">
960
+ <span class="cevvo-source-num">${l+1}</span>
961
+ <span class="cevvo-source-title">${this.escapeHtml(c.title||"Source")}</span>
962
+ ${n.link}
921
963
  </a>
922
964
  `).join("")}
923
965
  </div>
924
- `:"",n=e.feedback==="positive"?"feedback-positive":e.feedback==="negative"?"feedback-negative":"",c=e.role==="assistant"&&e.content&&!e.isLoading?`
925
- <div class="cevvo-actions ${n}" data-message-id="${e.messageId||""}">
926
- <button class="cevvo-copy-btn" title="Copy">${i.copy}</button>
927
- <button class="cevvo-thumbs-up ${e.feedback==="positive"?"active":""}" title="Helpful">${i.thumbsUp}</button>
928
- <button class="cevvo-thumbs-down ${e.feedback==="negative"?"active":""}" title="Not helpful">${i.thumbsDown}</button>
966
+ `:"",i=o.feedback==="positive"?"feedback-positive":o.feedback==="negative"?"feedback-negative":"",r=o.role==="assistant"&&o.content&&!o.isLoading?`
967
+ <div class="cevvo-actions ${i}" data-message-id="${o.messageId||""}">
968
+ <button class="cevvo-copy-btn" title="Copy">${n.copy}</button>
969
+ <button class="cevvo-thumbs-up ${o.feedback==="positive"?"active":""}" title="Helpful">${n.thumbsUp}</button>
970
+ <button class="cevvo-thumbs-down ${o.feedback==="negative"?"active":""}" title="Not helpful">${n.thumbsDown}</button>
929
971
  </div>
930
972
  `:"";return`
931
- <div class="cevvo-message ${e.role}" data-msg-id="${e.id}">
932
- <div class="cevvo-avatar ${e.role}">${o}</div>
973
+ <div class="cevvo-message ${o.role}" data-msg-id="${o.id}">
974
+ <div class="cevvo-avatar ${o.role}">${e}</div>
933
975
  <div class="cevvo-message-content">
934
- <div class="cevvo-bubble ${e.role}">${a}</div>
976
+ <div class="cevvo-bubble ${o.role}">${t}</div>
935
977
  ${s}
936
- ${c}
978
+ ${r}
937
979
  </div>
938
980
  </div>
939
- `}async submitFeedback(e,o){if(e)try{await fetch(`${this.config.apiUrl}/widget/feedback`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({message_id:e,rating:o,project_id:this.config.projectId})})}catch(a){console.error("Feedback error:",a)}}formatContent(e){return this.escapeHtml(e).replace(/\n/g,"<br>").replace(/\*\*(.*?)\*\*/g,"<strong>$1</strong>").replace(/\*(.*?)\*/g,"<em>$1</em>").replace(/`(.*?)`/g,"<code>$1</code>")}escapeHtml(e){const o=document.createElement("div");return o.textContent=e,o.innerHTML}}async function g(t,e,o){const a=o||p;try{const s=await fetch(`${a}/widget/config?project_id=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-API-Key":e}});if(!s.ok)return console.warn("[CevvoWidget] Failed to fetch config:",s.status),null;const n=await s.json();return{mode:n.mode,buttonText:n.buttonText,buttonPosition:n.position,projectColor:n.primaryColor,buttonBgColor:n.primaryColor,theme:n.theme||"light",modalTitle:n.modalTitle,modalSubtitle:n.modalSubtitle,modalExampleQuestions:n.exampleQuestions||[],welcomeMessage:n.welcomeMessage}}catch(s){return console.warn("[CevvoWidget] Error fetching config:",s.message),null}}window.CevvoWidget={init:async(t={})=>{if(t.projectId&&t.apiKey){const e=await g(t.projectId,t.apiKey,t.apiUrl);e&&(t={...t,...e})}return new h(t)},initWithRemoteConfig:async(t,e,o)=>{const a=await g(t,e,o),s={projectId:t,apiKey:e,apiUrl:o,...a};return new h(s)},testCredentials:async(t,e,o)=>{const a=o||p;try{const s=await fetch(`${a}/widget/config?project_id=${encodeURIComponent(t)}`,{method:"GET",headers:{"X-API-Key":e}});return{success:s.ok,status:s.status,data:s.ok?await s.json():null}}catch(s){return{success:!1,status:0,error:s.message}}}},document.addEventListener("DOMContentLoaded",async()=>{const t=document.querySelector("script[data-cevvo-project-id]");if(t){const e=t.getAttribute("data-cevvo-project-id")||"",o=t.getAttribute("data-cevvo-api-key")||"",a=t.getAttribute("data-cevvo-api-url")||void 0;let s=null;e&&o&&(s=await g(e,o,a));const n={projectId:e,apiKey:o,apiUrl:a,...s,...t.getAttribute("data-cevvo-project-name")&&{projectName:t.getAttribute("data-cevvo-project-name")},...t.getAttribute("data-cevvo-project-color")&&{projectColor:t.getAttribute("data-cevvo-project-color")},...t.getAttribute("data-cevvo-button-text")&&{buttonText:t.getAttribute("data-cevvo-button-text")},...t.getAttribute("data-cevvo-button-bg-color")&&{buttonBgColor:t.getAttribute("data-cevvo-button-bg-color")},...t.getAttribute("data-cevvo-modal-title")&&{modalTitle:t.getAttribute("data-cevvo-modal-title")},...t.getAttribute("data-cevvo-modal-placeholder")&&{modalPlaceholder:t.getAttribute("data-cevvo-modal-placeholder")}},c=t.getAttribute("data-cevvo-example-questions");if(c)try{n.modalExampleQuestions=JSON.parse(c)}catch{}new h(n)}})})()})();
981
+ `}async submitFeedback(o,e){if(o)try{await fetch(`${this.config.apiUrl}/widget/feedback`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:JSON.stringify({message_id:o,rating:e,project_id:this.config.projectId})})}catch(t){console.error("Feedback error:",t)}}formatContent(o){let e=this.escapeHtml(o);return e=e.replace(/```(\w*)\n([\s\S]*?)```/g,(t,s,i)=>`<pre class="cevvo-code-block"><code>${i.trim()}</code></pre>`),e=e.replace(/`([^`]+)`/g,'<code class="cevvo-inline-code">$1</code>'),e=e.replace(/\*\*(.*?)\*\*/g,"<strong>$1</strong>"),e=e.replace(/\*(.*?)\*/g,"<em>$1</em>"),e=e.replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener" style="color:var(--cevvo-accent,#2563eb);text-decoration:underline;">$1</a>'),e=e.replace(/^(\d+)\.\s+(.+)$/gm,'<li style="margin-left:1.2em;list-style:decimal;">$2</li>'),e=e.replace(/^[-•]\s+(.+)$/gm,'<li style="margin-left:1.2em;list-style:disc;">$1</li>'),e=e.replace(/\n/g,"<br>"),e=e.replace(/<pre class="cevvo-code-block"><code>([\s\S]*?)<\/code><\/pre>/g,(t,s)=>`<pre class="cevvo-code-block"><code>${s.replace(/<br>/g,`
982
+ `)}</code></pre>`),e}escapeHtml(o){const e=document.createElement("div");return e.textContent=o,e.innerHTML}}async function g(a,o,e){const t=e||p;try{const s=await fetch(`${t}/widget/config?project_id=${encodeURIComponent(a)}`,{method:"GET",headers:{"X-API-Key":o}});if(!s.ok)return console.warn("[CevvoWidget] Failed to fetch config:",s.status),null;const i=await s.json();return{mode:i.mode,buttonText:i.buttonText,buttonPosition:i.position,projectColor:i.primaryColor,buttonBgColor:i.primaryColor,theme:i.theme||"light",modalTitle:i.modalTitle,modalSubtitle:i.modalSubtitle,modalExampleQuestions:i.exampleQuestions||[],welcomeMessage:i.welcomeMessage}}catch(s){return console.warn("[CevvoWidget] Error fetching config:",s.message),null}}window.CevvoWidget={init:async(a={})=>{if(a.projectId&&a.apiKey){const o=await g(a.projectId,a.apiKey,a.apiUrl);if(o)for(const[e,t]of Object.entries(o))t!=null&&t!==""&&(a[e]=t)}return new h(a)},initWithRemoteConfig:async(a,o,e)=>{const t=e||p,s=await g(a,o,t),i={};if(s)for(const[d,c]of Object.entries(s))c!=null&&c!==""&&(i[d]=c);const r={projectId:a,apiKey:o,apiUrl:t,...i};return new h(r)},testCredentials:async(a,o,e)=>{const t=e||p;try{const s=await fetch(`${t}/widget/config?project_id=${encodeURIComponent(a)}`,{method:"GET",headers:{"X-API-Key":o}});return{success:s.ok,status:s.status,data:s.ok?await s.json():null}}catch(s){return{success:!1,status:0,error:s.message}}}},document.addEventListener("DOMContentLoaded",async()=>{const a=document.querySelector("script[data-cevvo-project-id]");if(a){const o=a.getAttribute("data-cevvo-project-id")||"",e=a.getAttribute("data-cevvo-api-key")||"",t=a.getAttribute("data-cevvo-api-url")||void 0;let s=null;o&&e&&(s=await g(o,e,t));const i={projectId:o,apiKey:e,apiUrl:t,...s,...a.getAttribute("data-cevvo-project-name")&&{projectName:a.getAttribute("data-cevvo-project-name")},...a.getAttribute("data-cevvo-project-color")&&{projectColor:a.getAttribute("data-cevvo-project-color")},...a.getAttribute("data-cevvo-button-text")&&{buttonText:a.getAttribute("data-cevvo-button-text")},...a.getAttribute("data-cevvo-button-bg-color")&&{buttonBgColor:a.getAttribute("data-cevvo-button-bg-color")},...a.getAttribute("data-cevvo-modal-title")&&{modalTitle:a.getAttribute("data-cevvo-modal-title")},...a.getAttribute("data-cevvo-modal-placeholder")&&{modalPlaceholder:a.getAttribute("data-cevvo-modal-placeholder")}},r=a.getAttribute("data-cevvo-example-questions");if(r)try{i.modalExampleQuestions=JSON.parse(r)}catch{}new h(i)}})})()})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cevvo-widget",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "Cevvo Widget - AI-powered chat for your docs",
5
5
  "type": "module",
6
6
  "main": "dist/widget.js",