cevvo-widget 1.0.9 → 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 +46 -22
  2. package/package.json +1 -1
package/dist/widget.js CHANGED
@@ -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;
@@ -836,7 +859,7 @@
836
859
  border-color: #38383a;
837
860
  color: #e5e5ea;
838
861
  }
839
- `;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=`${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 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`
840
863
  <div class="cevvo-modal">
841
864
  <div class="cevvo-modal-header">
842
865
  <div class="cevvo-header-info">
@@ -855,7 +878,7 @@
855
878
  <div class="cevvo-empty-state">
856
879
  <div class="cevvo-empty-icon">${n.sparkle}</div>
857
880
  <h3>${this.escapeHtml(this.config.welcomeMessage)}</h3>
858
- ${e?`<div class="cevvo-example-questions">${e}</div>`:""}
881
+ ${o?`<div class="cevvo-example-questions">${o}</div>`:""}
859
882
  </div>
860
883
  </div>
861
884
  <div class="cevvo-modal-footer">
@@ -867,7 +890,7 @@
867
890
  <p class="cevvo-powered">Powered by <a href="https://cevvo.ai" target="_blank" rel="noopener">Cevvo</a></p>
868
891
  </div>
869
892
  </div>
870
- `}renderModalMode(){const e=this.config.modalDescription||this.config.modalSubtitle||"Ask me anything about the documentation.";return`
893
+ `}renderModalMode(){const o=this.config.modalDescription||this.config.modalSubtitle||"Ask me anything about the documentation.";return`
871
894
  <div class="cevvo-modal">
872
895
  <div class="cevvo-modal-header">
873
896
  <div class="cevvo-header-info">
@@ -882,7 +905,7 @@
882
905
  </div>
883
906
  </div>
884
907
  <div class="cevvo-modal-description" style="padding: 0 24px;">
885
- ${e}
908
+ ${o}
886
909
  </div>
887
910
  <div class="cevvo-modal-body">
888
911
  </div>
@@ -914,25 +937,25 @@
914
937
  </div>
915
938
  </div>
916
939
  </div>
917
- `}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 i=s.dataset.messageId,r=a.closest(".cevvo-message"),d=r==null?void 0:r.dataset.msgId,c=this.messages.find(l=>l.id===d);if(a.classList.contains("cevvo-copy-btn")&&(c!=null&&c.content)&&(navigator.clipboard.writeText(c.content),a.innerHTML=n.check,setTimeout(()=>{a.innerHTML=n.copy},2e3)),a.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(a.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",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 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(`
918
- `);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(o,{content:d,isLoading:!1})),v.sources&&(c=v.sources),v.question_answer_id&&(l=v.question_answer_id)}catch{}}}this.updateMessage(o,{content:d||"I'm sorry, I couldn't generate a response.",sources:c,messageId:l,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=`
919
942
  <div class="cevvo-empty-state">
920
943
  <div class="cevvo-empty-icon">${n.sparkle}</div>
921
944
  <h3>${this.escapeHtml(this.config.welcomeMessage)}</h3>
922
945
  ${this.config.modalExampleQuestions.length?`
923
946
  <div class="cevvo-example-questions">
924
- ${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("")}
925
948
  </div>
926
949
  `:""}
927
950
  </div>
928
951
  `;return}this.messagesContainer.innerHTML=`
929
952
  <div class="cevvo-messages">
930
- ${this.messages.map(e=>this.renderMessage(e)).join("")}
953
+ ${this.messages.map(o=>this.renderMessage(o)).join("")}
931
954
  </div>
932
- `,this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight}renderMessage(e){var d;const o=e.role==="assistant"?n.cevvoLogo:n.user,a=e.isLoading?'<div class="cevvo-typing"><span></span><span></span><span></span></div>':this.formatContent(e.content),s=(d=e.sources)!=null&&d.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?`
933
956
  <div class="cevvo-sources">
934
957
  <div class="cevvo-sources-header">${n.link} Sources</div>
935
- ${e.sources.map((c,l)=>`
958
+ ${o.sources.map((c,l)=>`
936
959
  <a href="${this.escapeHtml(c.source_url||c.url||"#")}" target="_blank" rel="noopener" class="cevvo-source-link">
937
960
  <span class="cevvo-source-num">${l+1}</span>
938
961
  <span class="cevvo-source-title">${this.escapeHtml(c.title||"Source")}</span>
@@ -940,19 +963,20 @@
940
963
  </a>
941
964
  `).join("")}
942
965
  </div>
943
- `:"",i=e.feedback==="positive"?"feedback-positive":e.feedback==="negative"?"feedback-negative":"",r=e.role==="assistant"&&e.content&&!e.isLoading?`
944
- <div class="cevvo-actions ${i}" data-message-id="${e.messageId||""}">
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||""}">
945
968
  <button class="cevvo-copy-btn" title="Copy">${n.copy}</button>
946
- <button class="cevvo-thumbs-up ${e.feedback==="positive"?"active":""}" title="Helpful">${n.thumbsUp}</button>
947
- <button class="cevvo-thumbs-down ${e.feedback==="negative"?"active":""}" title="Not helpful">${n.thumbsDown}</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>
948
971
  </div>
949
972
  `:"";return`
950
- <div class="cevvo-message ${e.role}" data-msg-id="${e.id}">
951
- <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>
952
975
  <div class="cevvo-message-content">
953
- <div class="cevvo-bubble ${e.role}">${a}</div>
976
+ <div class="cevvo-bubble ${o.role}">${t}</div>
954
977
  ${s}
955
978
  ${r}
956
979
  </div>
957
980
  </div>
958
- `}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 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(t={})=>{if(t.projectId&&t.apiKey){const e=await g(t.projectId,t.apiKey,t.apiUrl);if(e)for(const[o,a]of Object.entries(e))a!=null&&a!==""&&(t[o]=a)}return new h(t)},initWithRemoteConfig:async(t,e,o)=>{const a=await g(t,e,o),s={};if(a)for(const[r,d]of Object.entries(a))d!=null&&d!==""&&(s[r]=d);const i={projectId:t,apiKey:e,apiUrl:o,...s};return new h(i)},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 i={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")}},r=t.getAttribute("data-cevvo-example-questions");if(r)try{i.modalExampleQuestions=JSON.parse(r)}catch{}new h(i)}})})()})();
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.9",
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",