@heedb/web-sdk 0.1.7 → 1.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.
- package/README.md +46 -4
- package/dist/index.cjs +18 -2
- package/dist/index.js +18 -2
- package/dist/widget.js +112 -96
- package/package.json +1 -1
- package/widget.js +112 -96
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ The fastest way — no build step, no dependencies. Add one line before `</body>
|
|
|
22
22
|
|
|
23
23
|
> **Important:** `data-host` is required when loading from a CDN. It tells the widget where to send API requests. Omit it only when the script is served from the same domain as your Heedb instance.
|
|
24
24
|
|
|
25
|
-
A floating chat button appears in the bottom-right corner. That's it.
|
|
25
|
+
A floating chat button appears in the bottom-right corner. That's it. Customize the look, trigger mode, and behavior from your [dashboard](https://heedb.com/app/customization).
|
|
26
26
|
|
|
27
27
|
### npm
|
|
28
28
|
|
|
@@ -399,16 +399,18 @@ Use the CDN script tag — no build tools needed:
|
|
|
399
399
|
|
|
400
400
|
For verified identity on static sites, you'll need a small server endpoint that returns the `userHash` — see the React + API route example above.
|
|
401
401
|
|
|
402
|
+
> **Tip:** To pin a specific major version on the CDN, use `https://cdn.jsdelivr.net/npm/@heedb/web-sdk@1/widget.js`. Without the version pin, you always get the latest release.
|
|
403
|
+
|
|
402
404
|
---
|
|
403
405
|
|
|
404
406
|
## What the widget does
|
|
405
407
|
|
|
406
|
-
The widget adds a
|
|
408
|
+
The widget adds a trigger button to your page with up to three tabs:
|
|
407
409
|
|
|
408
410
|
| Tab | Description | Requires |
|
|
409
411
|
|-----|-------------|----------|
|
|
410
412
|
| **Message** | Contact form — name, email, and a message. Creates a new support thread. Fields are hidden when the user is identified. | Nothing |
|
|
411
|
-
| **Privacy** | GDPR/privacy request form — data export, deletion, or opt-out. | Nothing |
|
|
413
|
+
| **Privacy** | GDPR/privacy request form — data export, deletion, or opt-out. Can be hidden via dashboard settings. | Nothing |
|
|
412
414
|
| **Messages** | Conversation history — shows open threads. | Verified identity (`userHash`) |
|
|
413
415
|
|
|
414
416
|
**The full conversation loop:**
|
|
@@ -422,6 +424,46 @@ The widget adds a floating button to your page with three tabs:
|
|
|
422
424
|
|
|
423
425
|
---
|
|
424
426
|
|
|
427
|
+
## Trigger modes
|
|
428
|
+
|
|
429
|
+
The widget supports three trigger modes, configured in your dashboard under **Customization**:
|
|
430
|
+
|
|
431
|
+
| Mode | Description |
|
|
432
|
+
|------|-------------|
|
|
433
|
+
| **Floating** (default) | A round button fixed in the bottom-right or bottom-left corner |
|
|
434
|
+
| **Tag** | A vertical tab on the left or right edge of the page (e.g. "Talk to us!") |
|
|
435
|
+
| **Embedded** | No visible button — you provide a CSS selector for an existing element on your page that opens the widget when clicked |
|
|
436
|
+
|
|
437
|
+
All trigger modes support a custom SVG icon or emoji, plus optional button text.
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Customization
|
|
442
|
+
|
|
443
|
+
All visual customization is done through the [dashboard](https://heedb.com/app/customization) — no code changes needed. Available options:
|
|
444
|
+
|
|
445
|
+
| Option | Description |
|
|
446
|
+
|--------|-------------|
|
|
447
|
+
| **Theme mode** | Light, dark, or system (follows OS preference) |
|
|
448
|
+
| **Colors** | Primary, text, and background colors — separate sets for light and dark mode |
|
|
449
|
+
| **Border radius** | Panel corner rounding (0–24px) |
|
|
450
|
+
| **Button radius** | Trigger button rounding (0–50px / full circle) |
|
|
451
|
+
| **Font family** | Custom font stack |
|
|
452
|
+
| **Header title** | Custom panel title (e.g. "Talk to us!") |
|
|
453
|
+
| **Trigger icon** | Custom SVG icon for the trigger button |
|
|
454
|
+
| **Trigger emoji** | Emoji for the trigger (default: 💬) |
|
|
455
|
+
| **Trigger text** | Label next to the icon (tag mode and floating with label) |
|
|
456
|
+
| **Position** | Bottom-right or bottom-left (floating), right or left edge (tag) |
|
|
457
|
+
| **Privacy tab** | Show or hide the privacy/GDPR tab |
|
|
458
|
+
| **Custom CSS** | Inject custom CSS to override any widget style |
|
|
459
|
+
| **Custom labels** | Localized overrides for tab labels, placeholders, and empty state text (en/es/pt) |
|
|
460
|
+
|
|
461
|
+
### Language
|
|
462
|
+
|
|
463
|
+
The widget auto-detects the page language from the `<html lang>` attribute and supports English, Spanish, and Portuguese. You can override individual labels with localized strings in the dashboard.
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
425
467
|
## Configuration reference
|
|
426
468
|
|
|
427
469
|
### Script tag attributes
|
|
@@ -447,7 +489,7 @@ The widget adds a floating button to your page with three tabs:
|
|
|
447
489
|
|---|---|---|---|
|
|
448
490
|
| `init()` called | No | Yes (email + name) | Yes (email + name + userHash) |
|
|
449
491
|
| Contact form visible | Yes (full form) | Yes (message only) | Yes (message only) |
|
|
450
|
-
| Privacy tab visible | Yes | Yes | Yes |
|
|
492
|
+
| Privacy tab visible | Yes (unless hidden in dashboard) | Yes (unless hidden) | Yes (unless hidden) |
|
|
451
493
|
| Messages tab visible | No | No | Yes |
|
|
452
494
|
| Name/email fields | Shown | Hidden | Hidden |
|
|
453
495
|
|
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
var DEFAULT_HOST = "https://heedb.com";
|
|
27
|
+
var CDN_WIDGET_URL = "https://cdn.jsdelivr.net/npm/@heedb/web-sdk/widget.js";
|
|
27
28
|
var Heedb = {
|
|
28
29
|
_scriptLoaded: false,
|
|
29
30
|
/**
|
|
@@ -39,7 +40,7 @@ var Heedb = {
|
|
|
39
40
|
const host = (_a = opts.host) != null ? _a : DEFAULT_HOST;
|
|
40
41
|
if (!this._scriptLoaded) {
|
|
41
42
|
const script = document.createElement("script");
|
|
42
|
-
script.src =
|
|
43
|
+
script.src = CDN_WIDGET_URL;
|
|
43
44
|
script.setAttribute("data-api-key", opts.apiKey);
|
|
44
45
|
script.setAttribute("data-host", host);
|
|
45
46
|
script.onload = () => {
|
|
@@ -51,6 +52,20 @@ var Heedb = {
|
|
|
51
52
|
this._identify(opts);
|
|
52
53
|
}
|
|
53
54
|
},
|
|
55
|
+
/**
|
|
56
|
+
* Clear the current user's identity and reset the widget to anonymous mode.
|
|
57
|
+
* Call this on logout to prevent the next user from seeing stale data.
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* Heedb.reset();
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
reset() {
|
|
64
|
+
const w = window;
|
|
65
|
+
if (w.Heedb && typeof w.Heedb.reset === "function") {
|
|
66
|
+
w.Heedb.reset();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
54
69
|
/** @internal */
|
|
55
70
|
_identify(opts) {
|
|
56
71
|
const w = window;
|
|
@@ -58,7 +73,8 @@ var Heedb = {
|
|
|
58
73
|
w.Heedb.init({
|
|
59
74
|
email: opts.email,
|
|
60
75
|
name: opts.name,
|
|
61
|
-
userHash: opts.userHash
|
|
76
|
+
userHash: opts.userHash,
|
|
77
|
+
lang: opts.lang
|
|
62
78
|
});
|
|
63
79
|
}
|
|
64
80
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
var DEFAULT_HOST = "https://heedb.com";
|
|
3
|
+
var CDN_WIDGET_URL = "https://cdn.jsdelivr.net/npm/@heedb/web-sdk/widget.js";
|
|
3
4
|
var Heedb = {
|
|
4
5
|
_scriptLoaded: false,
|
|
5
6
|
/**
|
|
@@ -15,7 +16,7 @@ var Heedb = {
|
|
|
15
16
|
const host = (_a = opts.host) != null ? _a : DEFAULT_HOST;
|
|
16
17
|
if (!this._scriptLoaded) {
|
|
17
18
|
const script = document.createElement("script");
|
|
18
|
-
script.src =
|
|
19
|
+
script.src = CDN_WIDGET_URL;
|
|
19
20
|
script.setAttribute("data-api-key", opts.apiKey);
|
|
20
21
|
script.setAttribute("data-host", host);
|
|
21
22
|
script.onload = () => {
|
|
@@ -27,6 +28,20 @@ var Heedb = {
|
|
|
27
28
|
this._identify(opts);
|
|
28
29
|
}
|
|
29
30
|
},
|
|
31
|
+
/**
|
|
32
|
+
* Clear the current user's identity and reset the widget to anonymous mode.
|
|
33
|
+
* Call this on logout to prevent the next user from seeing stale data.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* Heedb.reset();
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
reset() {
|
|
40
|
+
const w = window;
|
|
41
|
+
if (w.Heedb && typeof w.Heedb.reset === "function") {
|
|
42
|
+
w.Heedb.reset();
|
|
43
|
+
}
|
|
44
|
+
},
|
|
30
45
|
/** @internal */
|
|
31
46
|
_identify(opts) {
|
|
32
47
|
const w = window;
|
|
@@ -34,7 +49,8 @@ var Heedb = {
|
|
|
34
49
|
w.Heedb.init({
|
|
35
50
|
email: opts.email,
|
|
36
51
|
name: opts.name,
|
|
37
|
-
userHash: opts.userHash
|
|
52
|
+
userHash: opts.userHash,
|
|
53
|
+
lang: opts.lang
|
|
38
54
|
});
|
|
39
55
|
}
|
|
40
56
|
}
|
package/dist/widget.js
CHANGED
|
@@ -1,156 +1,172 @@
|
|
|
1
|
-
/* Heedb Widget
|
|
2
|
-
"use strict";(()=>{(function(){var
|
|
3
|
-
.
|
|
4
|
-
position: fixed; bottom: 24px; ${
|
|
5
|
-
width: 52px; height: 52px; border-radius: ${
|
|
1
|
+
/* Heedb Widget v1.0.1 — https://heedb.com */
|
|
2
|
+
"use strict";(()=>{(function(){var te,ae,ne,se,oe;let L=document.currentScript||document.querySelector("script[data-api-key]"),A=(te=L==null?void 0:L.getAttribute("data-api-key"))!=null?te:"",Y=(ae=L==null?void 0:L.src)!=null?ae:"",z=(L==null?void 0:L.getAttribute("data-host"))||(Y?new URL(Y).origin:"");if(!A){console.warn("[Heedb] Missing data-api-key on <script> tag.");return}let ie=1,r={},b=!1,re={primary:"#18181b",text:"#18181b",bg:"#ffffff"},le={primary:"#e4e4e7",text:"#e4e4e7",bg:"#1a1a1a"},j={en:{contactTab:"Message",privacyTab:"Privacy",messagesTab:"Messages",nameLabel:"Name",emailLabel:"Email",messageLabel:"Message",namePlaceholder:"Jane Smith",emailPlaceholder:"jane@example.com",messagePlaceholder:"How can we help?",sendMessage:"Send message",sending:"Sending\u2026",fillAllFields:"Please fill in all fields.",messageSentTitle:"Message sent!",messageSentBody:"We'll get back to you soon. Check your inbox for a confirmation email.",networkError:"Network error. Please try again.",somethingWrong:"Something went wrong.",rateLimited:"Too many messages. Please wait a moment.",requestType:"Request type",deleteData:"Delete my data",accessData:"Access my data",exportData:"Export my data",correctData:"Correct my data",restrictProcessing:"Restrict processing",objectProcessing:"Object to processing",other:"Other",submitRequest:"Submit request",submitting:"Submitting\u2026",requestSubmittedTitle:"Request submitted!",requestSubmittedBody:"Your privacy request has been received. We'll respond within 30 days.",contactUs:"Contact us",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Just now",minutesAgo:"{mins}m ago",hoursAgo:"{hours}h ago",send:"Send",backToMessages:"\u2190 Back to messages",noThreadsAuth:"Send a message below to view your message history.",sendAMessage:"+ Send a message",sendNewMessage:"+ Send a new message",noOpenMessages:"No open messages yet.",loading:"Loading\u2026",failedToLoad:"Failed to load messages.",failedToLoadConvo:"Failed to load conversation.",failedToSend:"Failed to send.",typeReply:"Type a reply\u2026",privacyRequest:"Privacy request",message:"Message"},es:{contactTab:"Mensaje",privacyTab:"Privacidad",messagesTab:"Mensajes",nameLabel:"Nombre",emailLabel:"Correo",messageLabel:"Mensaje",namePlaceholder:"Mar\xEDa Garc\xEDa",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"\xBFC\xF3mo podemos ayudarte?",sendMessage:"Enviar mensaje",sending:"Enviando\u2026",fillAllFields:"Por favor, completa todos los campos.",messageSentTitle:"\xA1Mensaje enviado!",messageSentBody:"Te responderemos pronto. Revisa tu bandeja de entrada para un correo de confirmaci\xF3n.",networkError:"Error de red. Int\xE9ntalo de nuevo.",somethingWrong:"Algo sali\xF3 mal.",rateLimited:"Demasiados mensajes. Espera un momento.",requestType:"Tipo de solicitud",deleteData:"Eliminar mis datos",accessData:"Acceder a mis datos",exportData:"Exportar mis datos",correctData:"Corregir mis datos",restrictProcessing:"Restringir procesamiento",objectProcessing:"Oponerse al procesamiento",other:"Otro",submitRequest:"Enviar solicitud",submitting:"Enviando\u2026",requestSubmittedTitle:"\xA1Solicitud enviada!",requestSubmittedBody:"Tu solicitud de privacidad ha sido recibida. Responderemos en un plazo de 30 d\xEDas.",contactUs:"Cont\xE1ctanos",feedback:"Comentarios",poweredBy:"Impulsado por Heedb",justNow:"Ahora",minutesAgo:"hace {mins}m",hoursAgo:"hace {hours}h",send:"Enviar",backToMessages:"\u2190 Volver a mensajes",noThreadsAuth:"Env\xEDa un mensaje para ver tu historial.",sendAMessage:"+ Enviar un mensaje",sendNewMessage:"+ Enviar un nuevo mensaje",noOpenMessages:"No hay mensajes a\xFAn.",loading:"Cargando\u2026",failedToLoad:"No se pudieron cargar los mensajes.",failedToLoadConvo:"No se pudo cargar la conversaci\xF3n.",failedToSend:"No se pudo enviar.",typeReply:"Escribe una respuesta\u2026",privacyRequest:"Solicitud de privacidad",message:"Mensaje"},pt:{contactTab:"Mensagem",privacyTab:"Privacidade",messagesTab:"Mensagens",nameLabel:"Nome",emailLabel:"Email",messageLabel:"Mensagem",namePlaceholder:"Maria Silva",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"Como podemos ajudar?",sendMessage:"Enviar mensagem",sending:"Enviando\u2026",fillAllFields:"Por favor, preencha todos os campos.",messageSentTitle:"Mensagem enviada!",messageSentBody:"Responderemos em breve. Verifique sua caixa de entrada para um email de confirma\xE7\xE3o.",networkError:"Erro de rede. Tente novamente.",somethingWrong:"Algo deu errado.",rateLimited:"Muitas mensagens. Aguarde um momento.",requestType:"Tipo de solicita\xE7\xE3o",deleteData:"Excluir meus dados",accessData:"Acessar meus dados",exportData:"Exportar meus dados",correctData:"Corrigir meus dados",restrictProcessing:"Restringir processamento",objectProcessing:"Opor-se ao processamento",other:"Outro",submitRequest:"Enviar solicita\xE7\xE3o",submitting:"Enviando\u2026",requestSubmittedTitle:"Solicita\xE7\xE3o enviada!",requestSubmittedBody:"Sua solicita\xE7\xE3o de privacidade foi recebida. Responderemos em at\xE9 30 dias.",contactUs:"Fale conosco",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Agora",minutesAgo:"h\xE1 {mins}m",hoursAgo:"h\xE1 {hours}h",send:"Enviar",backToMessages:"\u2190 Voltar \xE0s mensagens",noThreadsAuth:"Envie uma mensagem para ver seu hist\xF3rico.",sendAMessage:"+ Enviar uma mensagem",sendNewMessage:"+ Enviar uma nova mensagem",noOpenMessages:"Nenhuma mensagem ainda.",loading:"Carregando\u2026",failedToLoad:"N\xE3o foi poss\xEDvel carregar as mensagens.",failedToLoadConvo:"N\xE3o foi poss\xEDvel carregar a conversa.",failedToSend:"N\xE3o foi poss\xEDvel enviar.",typeReply:"Digite uma resposta\u2026",privacyRequest:"Solicita\xE7\xE3o de privacidade",message:"Mensagem"}},R="en";function n(e){var t,a,o;return(o=(a=(t=j[R])==null?void 0:t[e])!=null?a:j.en[e])!=null?o:e}function O(e){if(e)return e[R]||e.en}function G(){var a;let e=L==null?void 0:L.getAttribute("data-lang");if(e&&e in j)return e;if(F&&F in j)return F;if(r.language&&r.language in j)return r.language;let t=(a=document.documentElement.lang)==null?void 0:a.slice(0,2);return t&&t in j?t:"en"}let F;function J(){return r.mode==="dark"?!0:r.mode==="light"?!1:r.mode==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches:!1}function de(){return b?le:re}function N(e,t){let a=r[e];return a!=null?String(a):t}let S=!1,E="contact",K="",P=(ne=localStorage.getItem("heedb_name"))!=null?ne:"",k=(se=localStorage.getItem("heedb_email"))!=null?se:"",M=(oe=localStorage.getItem("heedb_token"))!=null?oe:"",f=null,_=null;async function ce(e,t){try{let a=await W("/api/threads/token",{api_key:A,email:e,userHash:t});if(a.ok){let o=await a.json();if(o.widgetToken){M=o.widgetToken,localStorage.setItem("heedb_token",o.widgetToken);return}}M="",localStorage.removeItem("heedb_token")}catch(a){M="",localStorage.removeItem("heedb_token")}}window.Heedb={version:"1.0.1",init(e={}){e.lang&&(F=e.lang,R=G(),Z(),S&&f&&C()),e.name&&(P=e.name,localStorage.setItem("heedb_name",e.name)),e.email&&(k=e.email,localStorage.setItem("heedb_email",e.email),e.userHash?ce(e.email,e.userHash).then(()=>{q(),S&&f&&C()}):(q(),S&&f&&C()))},reset(){P="",k="",M="",localStorage.removeItem("heedb_name"),localStorage.removeItem("heedb_email"),localStorage.removeItem("heedb_token"),E="contact",S=!1,f&&(f.style.display="none"),q()}};function W(e,t){return fetch(`${z}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}function pe(e){let t=new URL(`${z}/api/threads`);return t.searchParams.set("api_key",A),t.searchParams.set("email",e),M&&t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function me(e){let t=new URL(`${z}/api/threads/${e}`);return t.searchParams.set("api_key",A),t.searchParams.set("email",k),t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function ge(e,t){return W(`/api/threads/${e}/reply`,{api_key:A,email:k,token:M,message:t})}async function ue(){var e;try{let t=new URL(`${z}/api/widget-config`);t.searchParams.set("api_key",A),t.searchParams.set("v",String(ie));let a=await fetch(t.toString());if(a.ok)return(e=(await a.json()).config)!=null?e:{}}catch(t){}return{}}function X(){var g,v;let e=de(),t=N(b?"darkPrimaryColor":"primaryColor",e.primary),a=N(b?"darkTextColor":"textColor",e.text),o=N(b?"darkBgColor":"bgColor",e.bg),i=(g=r.borderRadius)!=null?g:16,l=(v=r.buttonRadius)!=null?v:50,y=r.fontFamily||"system-ui, -apple-system, sans-serif",h=r.position==="bottom-left",c=l>=50?"50%":`${l}px`,p=Math.round(i*.5),d=r.triggerMode==="tag",m=r.triggerMode==="embedded"||d;return`
|
|
3
|
+
.heedb-btn {
|
|
4
|
+
position: fixed; bottom: 24px; ${h?"left: 24px":"right: 24px"}; z-index: 999998;
|
|
5
|
+
width: 52px; height: 52px; border-radius: ${c}; border: none;
|
|
6
6
|
background: ${t}; color: #fff; font-size: 22px; cursor: pointer;
|
|
7
7
|
box-shadow: 0 4px 16px rgba(0,0,0,.25);
|
|
8
|
-
display: ${
|
|
9
|
-
transition: transform .15s;
|
|
10
|
-
}
|
|
11
|
-
.
|
|
12
|
-
.
|
|
13
|
-
.
|
|
14
|
-
.
|
|
15
|
-
.
|
|
16
|
-
.
|
|
17
|
-
position: fixed !important; ${
|
|
18
|
-
transform: ${
|
|
19
|
-
transform-origin: ${
|
|
8
|
+
display: ${m?"none":"flex"}; align-items: center; justify-content: center;
|
|
9
|
+
font-family: ${y}; transition: transform .15s;
|
|
10
|
+
}
|
|
11
|
+
.heedb-btn:hover { transform: scale(1.08); }
|
|
12
|
+
.heedb-btn-label { font-size: 14px; font-weight: 600; margin-left: 6px; }
|
|
13
|
+
.heedb-btn-icon { display: flex; align-items: center; justify-content: center; }
|
|
14
|
+
.heedb-btn-icon svg { width: 22px; height: 22px; fill: currentColor; }
|
|
15
|
+
.heedb-btn:has(.heedb-btn-label) { width: auto; padding: 0 18px; gap: 4px; }
|
|
16
|
+
.heedb-tag {
|
|
17
|
+
position: fixed !important; ${h?"left: 0 !important":"right: 0 !important"}; top: 50% !important; z-index: 999998 !important;
|
|
18
|
+
transform: ${h?"rotate(90deg) translateX(-50%)":"rotate(-90deg) translateX(50%)"} !important;
|
|
19
|
+
transform-origin: ${h?"left bottom":"right bottom"} !important;
|
|
20
20
|
background: ${t}; color: #fff; border: none; cursor: pointer;
|
|
21
21
|
padding: 8px 18px; font-size: 13px; font-weight: 600;
|
|
22
|
-
font-family: ${
|
|
23
|
-
border-radius: ${Math.min(
|
|
22
|
+
font-family: ${y};
|
|
23
|
+
border-radius: ${Math.min(l,12)}px ${Math.min(l,12)}px 0 0;
|
|
24
24
|
box-shadow: 0 2px 12px rgba(0,0,0,.2);
|
|
25
25
|
display: flex; align-items: center; gap: 6px;
|
|
26
26
|
transition: opacity .15s;
|
|
27
27
|
}
|
|
28
|
-
.
|
|
29
|
-
.
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
.heedb-tag:hover { opacity: .9; }
|
|
29
|
+
.heedb-tag-icon { font-size: 16px; }
|
|
30
|
+
.heedb-tag-icon svg { width: 16px; height: 16px; fill: currentColor; }
|
|
31
|
+
.heedb-panel {
|
|
32
|
+
position: fixed; bottom: 88px; ${h?"left: 24px":"right: 24px"}; z-index: 999999;
|
|
33
|
+
width: 280px; max-height: 560px; border-radius: ${i}px;
|
|
34
|
+
background: ${o}; box-shadow: 0 8px 32px rgba(0,0,0,.18);
|
|
34
35
|
display: flex; flex-direction: column; overflow: hidden;
|
|
35
|
-
font-family: ${
|
|
36
|
+
font-family: ${y}; font-size: 14px; color: ${a};
|
|
36
37
|
transition: opacity .15s, transform .15s;
|
|
37
38
|
}
|
|
38
|
-
.
|
|
39
|
+
.heedb-header {
|
|
39
40
|
background: ${t}; color: #fff; padding: 14px 16px;
|
|
40
41
|
display: flex; align-items: center; justify-content: space-between;
|
|
41
42
|
}
|
|
42
|
-
.
|
|
43
|
-
.
|
|
43
|
+
.heedb-header h2 { margin: 0; font-size: 15px; font-weight: 600; }
|
|
44
|
+
.heedb-close {
|
|
44
45
|
background: none; border: none; color: #fff; cursor: pointer;
|
|
45
46
|
font-size: 18px; line-height: 1; padding: 0;
|
|
46
47
|
}
|
|
47
|
-
.
|
|
48
|
-
display: flex; border-bottom: 1px solid ${
|
|
48
|
+
.heedb-tabs {
|
|
49
|
+
display: flex; border-bottom: 1px solid ${b?"#333":"#e4e4e7"};
|
|
49
50
|
}
|
|
50
|
-
.
|
|
51
|
+
.heedb-tab {
|
|
51
52
|
flex: 1; padding: 10px 0; border: none; background: none;
|
|
52
53
|
cursor: pointer; font-size: 13px; font-weight: 500; color: #71717a;
|
|
53
54
|
border-bottom: 2px solid transparent; margin-bottom: -1px;
|
|
54
55
|
}
|
|
55
|
-
.
|
|
56
|
-
.
|
|
57
|
-
.
|
|
58
|
-
.
|
|
56
|
+
.heedb-tab.active { color: ${a}; border-bottom-color: ${t}; }
|
|
57
|
+
.heedb-body { padding: 16px; overflow-y: auto; flex: 1; }
|
|
58
|
+
.heedb-label { display: block; font-size: 12px; font-weight: 600; color: #52525b; margin-bottom: 4px; }
|
|
59
|
+
.heedb-input, .heedb-textarea, .heedb-select {
|
|
59
60
|
width: 100%; box-sizing: border-box; padding: 8px 10px;
|
|
60
|
-
border: 1px solid ${
|
|
61
|
-
font-size: 13px; color: ${
|
|
62
|
-
font-family: inherit; background: ${
|
|
61
|
+
border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
|
|
62
|
+
font-size: 13px; color: ${a}; margin-bottom: 10px;
|
|
63
|
+
font-family: inherit; background: ${b?"#222":o};
|
|
63
64
|
}
|
|
64
|
-
.
|
|
65
|
-
.
|
|
65
|
+
.heedb-textarea { min-height: 80px; resize: vertical; }
|
|
66
|
+
.heedb-input:focus, .heedb-textarea:focus, .heedb-select:focus {
|
|
66
67
|
outline: none; border-color: ${t};
|
|
67
68
|
}
|
|
68
|
-
.
|
|
69
|
+
.heedb-btn-submit {
|
|
69
70
|
width: 100%; padding: 10px; background: ${t}; color: #fff;
|
|
70
|
-
border: none; border-radius: ${
|
|
71
|
+
border: none; border-radius: ${p}px; font-size: 14px; font-weight: 600;
|
|
71
72
|
cursor: pointer; transition: opacity .15s;
|
|
72
73
|
}
|
|
73
|
-
.
|
|
74
|
-
.
|
|
75
|
-
.
|
|
76
|
-
.
|
|
77
|
-
.
|
|
78
|
-
.
|
|
79
|
-
.
|
|
80
|
-
.
|
|
81
|
-
padding: 10px 12px; border: 1px solid ${
|
|
74
|
+
.heedb-btn-submit:hover { opacity: .85; }
|
|
75
|
+
.heedb-btn-submit:disabled { opacity: .5; cursor: not-allowed; }
|
|
76
|
+
.heedb-error { color: #ef4444; font-size: 12px; margin-bottom: 8px; }
|
|
77
|
+
.heedb-success { text-align: center; padding: 24px 8px; }
|
|
78
|
+
.heedb-success-icon { font-size: 36px; }
|
|
79
|
+
.heedb-success h3 { margin: 12px 0 6px; font-size: 15px; color: ${a}; }
|
|
80
|
+
.heedb-success p { margin: 0; color: #71717a; font-size: 13px; line-height: 1.5; }
|
|
81
|
+
.heedb-thread-item {
|
|
82
|
+
padding: 10px 12px; border: 1px solid ${b?"#333":"#e4e4e7"}; border-radius: ${p}px;
|
|
82
83
|
margin-bottom: 8px; cursor: pointer; display: block; color: inherit;
|
|
83
84
|
transition: background .1s; background: none;
|
|
84
85
|
}
|
|
85
|
-
.
|
|
86
|
-
.
|
|
87
|
-
.
|
|
88
|
-
.
|
|
89
|
-
.
|
|
90
|
-
.
|
|
91
|
-
.
|
|
92
|
-
.
|
|
93
|
-
.
|
|
94
|
-
width: 100%; padding: 8px; background: none; border: 1px solid ${
|
|
95
|
-
border-radius: ${
|
|
96
|
-
}
|
|
97
|
-
.
|
|
98
|
-
.
|
|
99
|
-
padding: 6px 16px; text-align: center; border-top: 1px solid ${
|
|
100
|
-
}
|
|
101
|
-
.
|
|
86
|
+
.heedb-thread-item:hover { background: ${b?"#252525":"#f4f4f5"}; }
|
|
87
|
+
.heedb-thread-label { font-size: 12px; color: #71717a; margin-bottom: 2px; }
|
|
88
|
+
.heedb-thread-text { font-size: 13px; color: ${a}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
89
|
+
.heedb-thread-meta { font-size: 11px; color: #a1a1aa; margin-top: 3px; }
|
|
90
|
+
.heedb-badge { display: inline-block; padding: 1px 6px; border-radius: 9999px; font-size: 10px; font-weight: 600; }
|
|
91
|
+
.heedb-badge-open { background: #d1fae5; color: #065f46; }
|
|
92
|
+
.heedb-badge-replied { background: #dbeafe; color: #1e40af; }
|
|
93
|
+
.heedb-new-msg { margin-top: 12px; padding-top: 12px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; }
|
|
94
|
+
.heedb-new-msg button {
|
|
95
|
+
width: 100%; padding: 8px; background: none; border: 1px solid ${b?"#444":"#d4d4d8"};
|
|
96
|
+
border-radius: ${p}px; font-size: 13px; cursor: pointer; color: ${b?"#999":"#52525b"};
|
|
97
|
+
}
|
|
98
|
+
.heedb-new-msg button:hover { background: ${b?"#252525":"#f4f4f5"}; }
|
|
99
|
+
.heedb-footer {
|
|
100
|
+
padding: 6px 16px; text-align: center; border-top: 1px solid ${b?"#333":"#f0f0f0"};
|
|
101
|
+
}
|
|
102
|
+
.heedb-footer a {
|
|
102
103
|
font-size: 10px; color: #a1a1aa; text-decoration: none; font-weight: 500;
|
|
103
104
|
}
|
|
104
|
-
.
|
|
105
|
+
.heedb-footer a:hover { color: #71717a; text-decoration: underline; }
|
|
105
106
|
|
|
106
107
|
/* Chat view */
|
|
107
|
-
.
|
|
108
|
+
.heedb-chat-back {
|
|
108
109
|
background: none; border: none; cursor: pointer; font-size: 13px;
|
|
109
110
|
color: ${t}; padding: 0; margin-bottom: 12px; font-weight: 500;
|
|
110
111
|
display: flex; align-items: center; gap: 4px;
|
|
111
112
|
}
|
|
112
|
-
.
|
|
113
|
-
.
|
|
113
|
+
.heedb-chat-back:hover { text-decoration: underline; }
|
|
114
|
+
.heedb-chat-messages {
|
|
114
115
|
display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px;
|
|
115
116
|
max-height: 320px; overflow-y: auto;
|
|
116
117
|
}
|
|
117
|
-
.
|
|
118
|
-
padding: 8px 12px; border-radius: ${Math.max(
|
|
118
|
+
.heedb-chat-bubble {
|
|
119
|
+
padding: 8px 12px; border-radius: ${Math.max(p,8)}px; font-size: 13px;
|
|
119
120
|
line-height: 1.45; max-width: 85%; word-wrap: break-word;
|
|
120
121
|
white-space: pre-wrap;
|
|
121
122
|
}
|
|
122
|
-
.
|
|
123
|
-
background: ${
|
|
123
|
+
.heedb-chat-inbound {
|
|
124
|
+
background: ${b?"#252525":"#f4f4f5"}; color: ${a}; align-self: flex-start;
|
|
124
125
|
border-bottom-left-radius: 4px;
|
|
125
126
|
}
|
|
126
|
-
.
|
|
127
|
+
.heedb-chat-outbound {
|
|
127
128
|
background: ${t}; color: #fff; align-self: flex-end;
|
|
128
129
|
border-bottom-right-radius: 4px;
|
|
129
130
|
}
|
|
130
|
-
.
|
|
131
|
+
.heedb-chat-time {
|
|
131
132
|
font-size: 10px; color: #a1a1aa; margin-top: 2px;
|
|
132
133
|
}
|
|
133
|
-
.
|
|
134
|
-
.
|
|
135
|
-
display: flex; gap: 8px; border-top: 1px solid ${
|
|
134
|
+
.heedb-chat-time-right { text-align: right; }
|
|
135
|
+
.heedb-chat-reply {
|
|
136
|
+
display: flex; gap: 8px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; padding-top: 12px;
|
|
136
137
|
}
|
|
137
|
-
.
|
|
138
|
-
flex: 1; padding: 8px 10px; border: 1px solid ${
|
|
139
|
-
font-size: 13px; font-family: inherit; color: ${
|
|
138
|
+
.heedb-chat-reply-input {
|
|
139
|
+
flex: 1; padding: 8px 10px; border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
|
|
140
|
+
font-size: 13px; font-family: inherit; color: ${a}; background: ${b?"#222":o};
|
|
140
141
|
resize: none; min-height: 36px; max-height: 80px; box-sizing: border-box;
|
|
141
142
|
}
|
|
142
|
-
.
|
|
143
|
-
.
|
|
143
|
+
.heedb-chat-reply-input:focus { outline: none; border-color: ${t}; }
|
|
144
|
+
.heedb-chat-send {
|
|
144
145
|
padding: 8px 14px; background: ${t}; color: #fff; border: none;
|
|
145
|
-
border-radius: ${
|
|
146
|
+
border-radius: ${p}px; font-size: 13px; font-weight: 600; cursor: pointer;
|
|
146
147
|
transition: opacity .15s; white-space: nowrap; align-self: flex-end;
|
|
147
148
|
}
|
|
148
|
-
.
|
|
149
|
-
.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
.heedb-chat-send:hover { opacity: .85; }
|
|
150
|
+
.heedb-chat-send:disabled { opacity: .5; cursor: not-allowed; }
|
|
151
|
+
|
|
152
|
+
/* Skeleton loading */
|
|
153
|
+
.heedb-skeleton { pointer-events: none; }
|
|
154
|
+
.heedb-skel-line {
|
|
155
|
+
background: ${b?"#333":"#e4e4e7"};
|
|
156
|
+
border-radius: 4px;
|
|
157
|
+
animation: heedb-pulse 1.5s ease-in-out infinite;
|
|
158
|
+
}
|
|
159
|
+
@keyframes heedb-pulse {
|
|
160
|
+
0%, 100% { opacity: 0.4; }
|
|
161
|
+
50% { opacity: 1; }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Body fade transition */
|
|
165
|
+
.heedb-body { transition: opacity .15s ease; }
|
|
166
|
+
`}function s(e,t={},a=[]){let o=document.createElement(e);for(let[i,l]of Object.entries(t))i==="class"?o.className=l:i==="style"?o.setAttribute("style",l):i.startsWith("on")&&typeof l=="function"?o.addEventListener(i.slice(2),l):o.setAttribute(i,String(l));for(let i of a)o.appendChild(typeof i=="string"?document.createTextNode(i):i);return o}function U(e,t,a=""){let o=document.createElement("input");return o.type=e,o.id=t,o.placeholder=a,o.className="heedb-input",o}function he(e,t=""){let a=document.createElement("textarea");return a.id=e,a.placeholder=t,a.className="heedb-textarea",a}function be(e,t){let a=document.createElement("select");a.id=e,a.className="heedb-select";for(let o of t){let i=document.createElement("option");i.value=o.value,i.textContent=o.label,a.appendChild(i)}return a}function C(){if(!f)return;let e=f.querySelector(".heedb-body");e.innerHTML="",E==="contact"?fe(e):E==="privacy"?xe(e):E==="threads"?ye(e):E==="thread-detail"&&Te(e),$&&($.style.display=E==="thread-detail"?"none":"flex")}function fe(e,t=""){let a=!!(P&&k),o=s("label",{class:"heedb-label"},[n("nameLabel")]),i=U("text","heedb-name",n("namePlaceholder"));P&&(i.value=P);let l=s("label",{class:"heedb-label"},[n("emailLabel")]),y=U("email","heedb-email",n("emailPlaceholder"));(t||k)&&(y.value=t||k);let h=O(r.messageLabel),c=h?s("label",{class:"heedb-label"},[h]):null,p=he("heedb-message",O(r.messagePlaceholder)||n("messagePlaceholder")),d=s("div",{class:"heedb-error",style:"display:none"}),m=s("button",{class:"heedb-btn-submit"},[n("sendMessage")]);m.onclick=async()=>{var x;let g=i.value.trim(),v=y.value.trim(),u=p.value.trim();if(d.style.display="none",!g||!v||!u){d.textContent=n("fillAllFields"),d.style.display="block";return}m.disabled=!0,m.textContent=n("sending");try{let T=await W("/api/contact",{api_key:A,name:g,email:v,message:u,lang:R});if(T.ok)k=v,localStorage.setItem("heedb_email",v),q(),Q(e,n("messageSentTitle"),n("messageSentBody"));else if(T.status===429){let w=parseInt((x=T.headers.get("Retry-After"))!=null?x:"60",10);d.textContent=n("rateLimited"),d.style.display="block",m.textContent=n("sendMessage"),setTimeout(()=>{m.disabled=!1,d.style.display="none"},w*1e3)}else{let w=await T.json();d.textContent=w.error||n("somethingWrong"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}}catch(T){d.textContent=n("networkError"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}},a?(c&&e.append(c),e.append(p,d,m)):(e.append(o,i,l,y),c&&e.append(c),e.append(p,d,m))}function xe(e){let t=!!(P&&k),a=s("label",{class:"heedb-label"},[n("nameLabel")]),o=U("text","heedb-priv-name",n("namePlaceholder"));P&&(o.value=P);let i=s("label",{class:"heedb-label"},[n("emailLabel")]),l=U("email","heedb-priv-email",n("emailPlaceholder"));k&&(l.value=k);let y=s("label",{class:"heedb-label"},[n("requestType")]),h=be("heedb-priv-type",[{value:"deletion",label:n("deleteData")},{value:"access",label:n("accessData")},{value:"portability",label:n("exportData")}]),c=s("div",{class:"heedb-error",style:"display:none"}),p=s("button",{class:"heedb-btn-submit"},[n("submitRequest")]);p.onclick=async()=>{var v;let d=o.value.trim(),m=l.value.trim(),g=h.value;if(c.style.display="none",!d||!m){c.textContent=n("fillAllFields"),c.style.display="block";return}p.disabled=!0,p.textContent=n("submitting");try{let u=await W("/api/privacy-request",{api_key:A,name:d,email:m,request_type:g,lang:R});if(u.ok)k=m,localStorage.setItem("heedb_email",m),q(),Q(e,n("requestSubmittedTitle"),n("requestSubmittedBody"));else if(u.status===429){let x=parseInt((v=u.headers.get("Retry-After"))!=null?v:"60",10);c.textContent=n("rateLimited"),c.style.display="block",p.textContent=n("submitRequest"),setTimeout(()=>{p.disabled=!1,c.style.display="none"},x*1e3)}else{let x=await u.json();c.textContent=x.error||n("somethingWrong"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}}catch(u){c.textContent=n("networkError"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}},t?e.append(y,h,c,p):e.append(a,o,i,l,y,h,c,p)}async function ye(e){var t;if(!M){e.innerHTML="";let a=s("p",{style:"color:#71717a;text-align:center;margin:8px 0;font-size:13px;line-height:1.5"},[n("noThreadsAuth")]),o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendAMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.append(a,o);return}e.innerHTML="";for(let a=0;a<3;a++){let o=s("div",{class:"heedb-thread-item heedb-skeleton"});o.append(s("div",{class:"heedb-skel-line",style:"width:40%;height:12px"}),s("div",{class:"heedb-skel-line",style:"width:80%;height:13px;margin-top:6px"}),s("div",{class:"heedb-skel-line",style:"width:30%;height:11px;margin-top:4px"})),e.appendChild(o)}try{let{threads:a}=await pe(k);if(e.innerHTML="",e.style.opacity="0",requestAnimationFrame(()=>{e.style.opacity="1"}),a.length===0){let l=s("p",{style:"color:#71717a;text-align:center;margin:8px 0"},[O(r.emptyStateText)||n("noOpenMessages")]);e.appendChild(l)}else for(let l of a){let y=s("span",{class:`heedb-badge heedb-badge-${l.status}`},[l.status]),h=s("div",{class:"heedb-thread-label"},[l.type==="privacy"?n("privacyRequest"):n("message")," \u2022 "]);h.appendChild(y);let c=s("div",{class:"heedb-thread-text"},[(t=l.preview)!=null?t:""]),p=new Date(l.createdAt).toLocaleDateString(),d=s("div",{class:"heedb-thread-meta"},[p]),m=s("div",{class:"heedb-thread-item"});m.append(h,c,d),m.onclick=()=>ve(l.id),e.appendChild(m)}let o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendNewMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.appendChild(o)}catch(a){e.innerHTML=`<p style="color:#ef4444;text-align:center">${n("failedToLoad")}</p>`}}function ve(e){K=e,E="thread-detail",C()}async function Te(e){e.innerHTML="",e.style.padding="12px";let t=s("div",{class:"heedb-skel-line",style:"width:50%;height:13px;margin-bottom:12px"});e.appendChild(t);let a=s("div",{style:"display:flex;flex-direction:column;gap:8px"}),o=["65%","50%","70%","45%"],i=["flex-start","flex-end","flex-start","flex-end"];for(let y=0;y<4;y++){let h=s("div",{style:`display:flex;flex-direction:column;align-items:${i[y]}`});h.appendChild(s("div",{class:"heedb-skel-line",style:`width:${o[y]};height:32px;border-radius:8px`})),a.appendChild(h)}e.appendChild(a);let l=s("button",{class:"heedb-chat-back"},[n("backToMessages")]);l.onclick=()=>{E="threads",B("threads"),C()};try{let h=(await me(K)).messages||[];e.innerHTML="",e.style.padding="12px",e.appendChild(l);let c=s("div",{class:"heedb-chat-messages"});for(let u of h){let x=u.direction==="inbound",T=s("div",{style:`display:flex;flex-direction:column;${x?"align-items:flex-start":"align-items:flex-end"}`}),w=s("div",{class:`heedb-chat-bubble ${x?"heedb-chat-inbound":"heedb-chat-outbound"}`},[we(u.body)]),H=s("div",{class:`heedb-chat-time ${x?"":"heedb-chat-time-right"}`},[ke(u.createdAt)]);T.append(w,H),c.appendChild(T)}e.appendChild(c),requestAnimationFrame(()=>{c.scrollTop=c.scrollHeight});let p=s("div",{class:"heedb-chat-reply"}),d=document.createElement("textarea");d.className="heedb-chat-reply-input",d.placeholder=n("typeReply"),d.rows=1,d.addEventListener("input",()=>{d.style.height="auto",d.style.height=Math.min(d.scrollHeight,80)+"px"});let m=s("button",{class:"heedb-chat-send"},[n("send")]),g=s("div",{class:"heedb-error",style:"display:none;margin-top:4px"});async function v(){let u=d.value.trim();if(u){m.disabled=!0,m.textContent="\u2026",g.style.display="none";try{let x=await ge(K,u);if(x.ok){let T=s("div",{style:"display:flex;flex-direction:column;align-items:flex-start"}),w=s("div",{class:"heedb-chat-bubble heedb-chat-inbound"},[u]),H=s("div",{class:"heedb-chat-time"},[n("justNow")]);T.append(w,H),c.appendChild(T),c.scrollTop=c.scrollHeight,d.value="",d.style.height="auto"}else{let T=await x.json();g.textContent=T.error||n("failedToSend"),g.style.display="block"}}catch(x){g.textContent=n("networkError"),g.style.display="block"}m.disabled=!1,m.textContent=n("send")}}m.onclick=v,d.addEventListener("keydown",u=>{u.key==="Enter"&&!u.shiftKey&&(u.preventDefault(),v())}),p.append(d,m),e.append(p,g),requestAnimationFrame(()=>d.focus())}catch(y){e.innerHTML="",e.appendChild(l),e.appendChild(s("p",{style:"color:#ef4444;text-align:center"},[n("failedToLoadConvo")]))}}function we(e){let t=e.split(`
|
|
167
|
+
`),a=[];for(let o of t){let i=o.trim();if(/^(On|Em|El|Le|Am|Il giorno) .+(<[^>]+@[^>]+>).*(wrote|escreveu|escribi|crit|schrieb|scritto)\s?:$/i.test(i)||/<[^>]+@[^>]+>/.test(i)&&i.endsWith(":")||/^-{3,}$/.test(i))break;/^>{1,}\s/.test(i)||a.push(o)}return a.join(`
|
|
168
|
+
`).trim()}function ke(e){let t=new Date(e),o=new Date().getTime()-t.getTime(),i=Math.floor(o/6e4);if(i<1)return n("justNow");if(i<60)return n("minutesAgo").replace("{mins}",String(i));let l=Math.floor(i/60);return l<24?n("hoursAgo").replace("{hours}",String(l)):t.toLocaleDateString()}function Q(e,t,a){e.innerHTML="";let o=s("div",{class:"heedb-success"});o.innerHTML=`
|
|
169
|
+
<div class="heedb-success-icon">\u2705</div>
|
|
154
170
|
<h3>${t}</h3>
|
|
155
|
-
<p>${
|
|
156
|
-
`,e.appendChild(
|
|
171
|
+
<p>${a}</p>
|
|
172
|
+
`,e.appendChild(o)}let $=null,D=null;function B(e){E=e,$&&$.querySelectorAll(".heedb-tab").forEach(t=>{t.classList.toggle("active",t.dataset.mode===e)})}function q(){D&&(D.style.display=k&&M?"":"none")}let I=null;function Z(){b=J(),I&&(I.textContent=X())}async function ee(){if(r=await ue(),R=G(),b=J(),I=document.createElement("style"),I.textContent=X(),document.head.appendChild(I),r.customCSS){let g=document.createElement("style");g.textContent=r.customCSS,document.head.appendChild(g)}r.mode==="system"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{Z(),S&&f&&C()});let e=r.triggerIcon?r.triggerIcon:r.triggerEmoji||"\u{1F4AC}",t=r.triggerText||"";if(_=s("button",{class:"heedb-btn",title:n("contactUs"),"aria-label":"Open contact widget"}),r.triggerIcon){let g=s("span",{class:"heedb-btn-icon"}),u=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(u){u.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(w=>w.remove());let x=document.createTreeWalker(u,NodeFilter.SHOW_ELEMENT),T;for(;T=x.nextNode();)for(let w of Array.from(T.attributes))(w.name.startsWith("on")||/^\s*javascript:/i.test(w.value))&&T.removeAttribute(w.name);g.appendChild(u)}_.appendChild(g)}else _.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));if(t&&_.appendChild(s("span",{class:"heedb-btn-label"},[t])),_.onclick=V,document.body.appendChild(_),r.triggerMode==="embedded"&&r.triggerSelector){let g=document.querySelector(r.triggerSelector);g&&g.addEventListener("click",v=>{v.preventDefault(),V()})}if(r.triggerMode==="tag"){let g=s("button",{class:"heedb-tag","aria-label":"Open contact widget"}),v=s("span",{class:"heedb-tag-icon"});if(r.triggerIcon){let x=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(x){x.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(H=>H.remove());let T=document.createTreeWalker(x,NodeFilter.SHOW_ELEMENT),w;for(;w=T.nextNode();)for(let H of Array.from(w.attributes))(H.name.startsWith("on")||/^\s*javascript:/i.test(H.value))&&w.removeAttribute(H.name);v.appendChild(x)}}else v.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));g.appendChild(v),g.appendChild(document.createTextNode(r.triggerText||n("feedback"))),g.onclick=V,document.body.appendChild(g)}f=s("div",{class:"heedb-panel",style:"display:none"});let a=s("div",{class:"heedb-header"}),o=s("h2",{},[r.headerTitle||n("contactUs")]),i=s("button",{class:"heedb-close","aria-label":"Close"},["\u2715"]);i.onclick=V,a.append(o,i),$=s("div",{class:"heedb-tabs"});let l=s("button",{class:"heedb-tab active","data-mode":"contact"},[O(r.contactTabLabel)||n("contactTab")]),h=r.showPrivacyTab!==!1?s("button",{class:"heedb-tab","data-mode":"privacy"},[n("privacyTab")]):null;D=s("button",{class:"heedb-tab","data-mode":"threads"},[n("messagesTab")]),D.style.display=k&&M?"":"none",l.onclick=()=>{B("contact"),C()},h&&(h.onclick=()=>{B("privacy"),C()}),D.onclick=()=>{B("threads"),C()},$.append(l),h&&$.append(h),$.append(D);let c=s("div",{class:"heedb-body"}),p=s("div",{class:"heedb-footer"}),d=new URLSearchParams({utm_source:"widget",utm_medium:"heedb-widget",utm_campaign:window.location.hostname}),m=s("a",{href:`https://heedb.com?${d.toString()}`,target:"_blank",rel:"noopener noreferrer"},[n("poweredBy")]);p.appendChild(m),f.append(a,$,c,p),document.body.appendChild(f)}function V(){S=!S,f&&(S?(f.style.display="flex",f.style.opacity="0",f.style.transform="translateY(8px)",requestAnimationFrame(()=>{f.style.opacity="1",f.style.transform="translateY(0)"}),k&&M&&E!=="privacy"&&E!=="thread-detail"&&(E="threads",B("threads")),C()):(f.style.opacity="0",f.style.transform="translateY(8px)",setTimeout(()=>{!S&&f&&(f.style.display="none")},150)))}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ee):ee()})();})();
|
package/package.json
CHANGED
package/widget.js
CHANGED
|
@@ -1,156 +1,172 @@
|
|
|
1
|
-
/* Heedb Widget
|
|
2
|
-
"use strict";(()=>{(function(){var
|
|
3
|
-
.
|
|
4
|
-
position: fixed; bottom: 24px; ${
|
|
5
|
-
width: 52px; height: 52px; border-radius: ${
|
|
1
|
+
/* Heedb Widget v1.0.1 — https://heedb.com */
|
|
2
|
+
"use strict";(()=>{(function(){var te,ae,ne,se,oe;let L=document.currentScript||document.querySelector("script[data-api-key]"),A=(te=L==null?void 0:L.getAttribute("data-api-key"))!=null?te:"",Y=(ae=L==null?void 0:L.src)!=null?ae:"",z=(L==null?void 0:L.getAttribute("data-host"))||(Y?new URL(Y).origin:"");if(!A){console.warn("[Heedb] Missing data-api-key on <script> tag.");return}let ie=1,r={},b=!1,re={primary:"#18181b",text:"#18181b",bg:"#ffffff"},le={primary:"#e4e4e7",text:"#e4e4e7",bg:"#1a1a1a"},j={en:{contactTab:"Message",privacyTab:"Privacy",messagesTab:"Messages",nameLabel:"Name",emailLabel:"Email",messageLabel:"Message",namePlaceholder:"Jane Smith",emailPlaceholder:"jane@example.com",messagePlaceholder:"How can we help?",sendMessage:"Send message",sending:"Sending\u2026",fillAllFields:"Please fill in all fields.",messageSentTitle:"Message sent!",messageSentBody:"We'll get back to you soon. Check your inbox for a confirmation email.",networkError:"Network error. Please try again.",somethingWrong:"Something went wrong.",rateLimited:"Too many messages. Please wait a moment.",requestType:"Request type",deleteData:"Delete my data",accessData:"Access my data",exportData:"Export my data",correctData:"Correct my data",restrictProcessing:"Restrict processing",objectProcessing:"Object to processing",other:"Other",submitRequest:"Submit request",submitting:"Submitting\u2026",requestSubmittedTitle:"Request submitted!",requestSubmittedBody:"Your privacy request has been received. We'll respond within 30 days.",contactUs:"Contact us",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Just now",minutesAgo:"{mins}m ago",hoursAgo:"{hours}h ago",send:"Send",backToMessages:"\u2190 Back to messages",noThreadsAuth:"Send a message below to view your message history.",sendAMessage:"+ Send a message",sendNewMessage:"+ Send a new message",noOpenMessages:"No open messages yet.",loading:"Loading\u2026",failedToLoad:"Failed to load messages.",failedToLoadConvo:"Failed to load conversation.",failedToSend:"Failed to send.",typeReply:"Type a reply\u2026",privacyRequest:"Privacy request",message:"Message"},es:{contactTab:"Mensaje",privacyTab:"Privacidad",messagesTab:"Mensajes",nameLabel:"Nombre",emailLabel:"Correo",messageLabel:"Mensaje",namePlaceholder:"Mar\xEDa Garc\xEDa",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"\xBFC\xF3mo podemos ayudarte?",sendMessage:"Enviar mensaje",sending:"Enviando\u2026",fillAllFields:"Por favor, completa todos los campos.",messageSentTitle:"\xA1Mensaje enviado!",messageSentBody:"Te responderemos pronto. Revisa tu bandeja de entrada para un correo de confirmaci\xF3n.",networkError:"Error de red. Int\xE9ntalo de nuevo.",somethingWrong:"Algo sali\xF3 mal.",rateLimited:"Demasiados mensajes. Espera un momento.",requestType:"Tipo de solicitud",deleteData:"Eliminar mis datos",accessData:"Acceder a mis datos",exportData:"Exportar mis datos",correctData:"Corregir mis datos",restrictProcessing:"Restringir procesamiento",objectProcessing:"Oponerse al procesamiento",other:"Otro",submitRequest:"Enviar solicitud",submitting:"Enviando\u2026",requestSubmittedTitle:"\xA1Solicitud enviada!",requestSubmittedBody:"Tu solicitud de privacidad ha sido recibida. Responderemos en un plazo de 30 d\xEDas.",contactUs:"Cont\xE1ctanos",feedback:"Comentarios",poweredBy:"Impulsado por Heedb",justNow:"Ahora",minutesAgo:"hace {mins}m",hoursAgo:"hace {hours}h",send:"Enviar",backToMessages:"\u2190 Volver a mensajes",noThreadsAuth:"Env\xEDa un mensaje para ver tu historial.",sendAMessage:"+ Enviar un mensaje",sendNewMessage:"+ Enviar un nuevo mensaje",noOpenMessages:"No hay mensajes a\xFAn.",loading:"Cargando\u2026",failedToLoad:"No se pudieron cargar los mensajes.",failedToLoadConvo:"No se pudo cargar la conversaci\xF3n.",failedToSend:"No se pudo enviar.",typeReply:"Escribe una respuesta\u2026",privacyRequest:"Solicitud de privacidad",message:"Mensaje"},pt:{contactTab:"Mensagem",privacyTab:"Privacidade",messagesTab:"Mensagens",nameLabel:"Nome",emailLabel:"Email",messageLabel:"Mensagem",namePlaceholder:"Maria Silva",emailPlaceholder:"maria@empresa.com",messagePlaceholder:"Como podemos ajudar?",sendMessage:"Enviar mensagem",sending:"Enviando\u2026",fillAllFields:"Por favor, preencha todos os campos.",messageSentTitle:"Mensagem enviada!",messageSentBody:"Responderemos em breve. Verifique sua caixa de entrada para um email de confirma\xE7\xE3o.",networkError:"Erro de rede. Tente novamente.",somethingWrong:"Algo deu errado.",rateLimited:"Muitas mensagens. Aguarde um momento.",requestType:"Tipo de solicita\xE7\xE3o",deleteData:"Excluir meus dados",accessData:"Acessar meus dados",exportData:"Exportar meus dados",correctData:"Corrigir meus dados",restrictProcessing:"Restringir processamento",objectProcessing:"Opor-se ao processamento",other:"Outro",submitRequest:"Enviar solicita\xE7\xE3o",submitting:"Enviando\u2026",requestSubmittedTitle:"Solicita\xE7\xE3o enviada!",requestSubmittedBody:"Sua solicita\xE7\xE3o de privacidade foi recebida. Responderemos em at\xE9 30 dias.",contactUs:"Fale conosco",feedback:"Feedback",poweredBy:"Powered by Heedb",justNow:"Agora",minutesAgo:"h\xE1 {mins}m",hoursAgo:"h\xE1 {hours}h",send:"Enviar",backToMessages:"\u2190 Voltar \xE0s mensagens",noThreadsAuth:"Envie uma mensagem para ver seu hist\xF3rico.",sendAMessage:"+ Enviar uma mensagem",sendNewMessage:"+ Enviar uma nova mensagem",noOpenMessages:"Nenhuma mensagem ainda.",loading:"Carregando\u2026",failedToLoad:"N\xE3o foi poss\xEDvel carregar as mensagens.",failedToLoadConvo:"N\xE3o foi poss\xEDvel carregar a conversa.",failedToSend:"N\xE3o foi poss\xEDvel enviar.",typeReply:"Digite uma resposta\u2026",privacyRequest:"Solicita\xE7\xE3o de privacidade",message:"Mensagem"}},R="en";function n(e){var t,a,o;return(o=(a=(t=j[R])==null?void 0:t[e])!=null?a:j.en[e])!=null?o:e}function O(e){if(e)return e[R]||e.en}function G(){var a;let e=L==null?void 0:L.getAttribute("data-lang");if(e&&e in j)return e;if(F&&F in j)return F;if(r.language&&r.language in j)return r.language;let t=(a=document.documentElement.lang)==null?void 0:a.slice(0,2);return t&&t in j?t:"en"}let F;function J(){return r.mode==="dark"?!0:r.mode==="light"?!1:r.mode==="system"?window.matchMedia("(prefers-color-scheme: dark)").matches:!1}function de(){return b?le:re}function N(e,t){let a=r[e];return a!=null?String(a):t}let S=!1,E="contact",K="",P=(ne=localStorage.getItem("heedb_name"))!=null?ne:"",k=(se=localStorage.getItem("heedb_email"))!=null?se:"",M=(oe=localStorage.getItem("heedb_token"))!=null?oe:"",f=null,_=null;async function ce(e,t){try{let a=await W("/api/threads/token",{api_key:A,email:e,userHash:t});if(a.ok){let o=await a.json();if(o.widgetToken){M=o.widgetToken,localStorage.setItem("heedb_token",o.widgetToken);return}}M="",localStorage.removeItem("heedb_token")}catch(a){M="",localStorage.removeItem("heedb_token")}}window.Heedb={version:"1.0.1",init(e={}){e.lang&&(F=e.lang,R=G(),Z(),S&&f&&C()),e.name&&(P=e.name,localStorage.setItem("heedb_name",e.name)),e.email&&(k=e.email,localStorage.setItem("heedb_email",e.email),e.userHash?ce(e.email,e.userHash).then(()=>{q(),S&&f&&C()}):(q(),S&&f&&C()))},reset(){P="",k="",M="",localStorage.removeItem("heedb_name"),localStorage.removeItem("heedb_email"),localStorage.removeItem("heedb_token"),E="contact",S=!1,f&&(f.style.display="none"),q()}};function W(e,t){return fetch(`${z}${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}function pe(e){let t=new URL(`${z}/api/threads`);return t.searchParams.set("api_key",A),t.searchParams.set("email",e),M&&t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function me(e){let t=new URL(`${z}/api/threads/${e}`);return t.searchParams.set("api_key",A),t.searchParams.set("email",k),t.searchParams.set("token",M),fetch(t.toString()).then(a=>a.json())}function ge(e,t){return W(`/api/threads/${e}/reply`,{api_key:A,email:k,token:M,message:t})}async function ue(){var e;try{let t=new URL(`${z}/api/widget-config`);t.searchParams.set("api_key",A),t.searchParams.set("v",String(ie));let a=await fetch(t.toString());if(a.ok)return(e=(await a.json()).config)!=null?e:{}}catch(t){}return{}}function X(){var g,v;let e=de(),t=N(b?"darkPrimaryColor":"primaryColor",e.primary),a=N(b?"darkTextColor":"textColor",e.text),o=N(b?"darkBgColor":"bgColor",e.bg),i=(g=r.borderRadius)!=null?g:16,l=(v=r.buttonRadius)!=null?v:50,y=r.fontFamily||"system-ui, -apple-system, sans-serif",h=r.position==="bottom-left",c=l>=50?"50%":`${l}px`,p=Math.round(i*.5),d=r.triggerMode==="tag",m=r.triggerMode==="embedded"||d;return`
|
|
3
|
+
.heedb-btn {
|
|
4
|
+
position: fixed; bottom: 24px; ${h?"left: 24px":"right: 24px"}; z-index: 999998;
|
|
5
|
+
width: 52px; height: 52px; border-radius: ${c}; border: none;
|
|
6
6
|
background: ${t}; color: #fff; font-size: 22px; cursor: pointer;
|
|
7
7
|
box-shadow: 0 4px 16px rgba(0,0,0,.25);
|
|
8
|
-
display: ${
|
|
9
|
-
transition: transform .15s;
|
|
10
|
-
}
|
|
11
|
-
.
|
|
12
|
-
.
|
|
13
|
-
.
|
|
14
|
-
.
|
|
15
|
-
.
|
|
16
|
-
.
|
|
17
|
-
position: fixed !important; ${
|
|
18
|
-
transform: ${
|
|
19
|
-
transform-origin: ${
|
|
8
|
+
display: ${m?"none":"flex"}; align-items: center; justify-content: center;
|
|
9
|
+
font-family: ${y}; transition: transform .15s;
|
|
10
|
+
}
|
|
11
|
+
.heedb-btn:hover { transform: scale(1.08); }
|
|
12
|
+
.heedb-btn-label { font-size: 14px; font-weight: 600; margin-left: 6px; }
|
|
13
|
+
.heedb-btn-icon { display: flex; align-items: center; justify-content: center; }
|
|
14
|
+
.heedb-btn-icon svg { width: 22px; height: 22px; fill: currentColor; }
|
|
15
|
+
.heedb-btn:has(.heedb-btn-label) { width: auto; padding: 0 18px; gap: 4px; }
|
|
16
|
+
.heedb-tag {
|
|
17
|
+
position: fixed !important; ${h?"left: 0 !important":"right: 0 !important"}; top: 50% !important; z-index: 999998 !important;
|
|
18
|
+
transform: ${h?"rotate(90deg) translateX(-50%)":"rotate(-90deg) translateX(50%)"} !important;
|
|
19
|
+
transform-origin: ${h?"left bottom":"right bottom"} !important;
|
|
20
20
|
background: ${t}; color: #fff; border: none; cursor: pointer;
|
|
21
21
|
padding: 8px 18px; font-size: 13px; font-weight: 600;
|
|
22
|
-
font-family: ${
|
|
23
|
-
border-radius: ${Math.min(
|
|
22
|
+
font-family: ${y};
|
|
23
|
+
border-radius: ${Math.min(l,12)}px ${Math.min(l,12)}px 0 0;
|
|
24
24
|
box-shadow: 0 2px 12px rgba(0,0,0,.2);
|
|
25
25
|
display: flex; align-items: center; gap: 6px;
|
|
26
26
|
transition: opacity .15s;
|
|
27
27
|
}
|
|
28
|
-
.
|
|
29
|
-
.
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
.heedb-tag:hover { opacity: .9; }
|
|
29
|
+
.heedb-tag-icon { font-size: 16px; }
|
|
30
|
+
.heedb-tag-icon svg { width: 16px; height: 16px; fill: currentColor; }
|
|
31
|
+
.heedb-panel {
|
|
32
|
+
position: fixed; bottom: 88px; ${h?"left: 24px":"right: 24px"}; z-index: 999999;
|
|
33
|
+
width: 280px; max-height: 560px; border-radius: ${i}px;
|
|
34
|
+
background: ${o}; box-shadow: 0 8px 32px rgba(0,0,0,.18);
|
|
34
35
|
display: flex; flex-direction: column; overflow: hidden;
|
|
35
|
-
font-family: ${
|
|
36
|
+
font-family: ${y}; font-size: 14px; color: ${a};
|
|
36
37
|
transition: opacity .15s, transform .15s;
|
|
37
38
|
}
|
|
38
|
-
.
|
|
39
|
+
.heedb-header {
|
|
39
40
|
background: ${t}; color: #fff; padding: 14px 16px;
|
|
40
41
|
display: flex; align-items: center; justify-content: space-between;
|
|
41
42
|
}
|
|
42
|
-
.
|
|
43
|
-
.
|
|
43
|
+
.heedb-header h2 { margin: 0; font-size: 15px; font-weight: 600; }
|
|
44
|
+
.heedb-close {
|
|
44
45
|
background: none; border: none; color: #fff; cursor: pointer;
|
|
45
46
|
font-size: 18px; line-height: 1; padding: 0;
|
|
46
47
|
}
|
|
47
|
-
.
|
|
48
|
-
display: flex; border-bottom: 1px solid ${
|
|
48
|
+
.heedb-tabs {
|
|
49
|
+
display: flex; border-bottom: 1px solid ${b?"#333":"#e4e4e7"};
|
|
49
50
|
}
|
|
50
|
-
.
|
|
51
|
+
.heedb-tab {
|
|
51
52
|
flex: 1; padding: 10px 0; border: none; background: none;
|
|
52
53
|
cursor: pointer; font-size: 13px; font-weight: 500; color: #71717a;
|
|
53
54
|
border-bottom: 2px solid transparent; margin-bottom: -1px;
|
|
54
55
|
}
|
|
55
|
-
.
|
|
56
|
-
.
|
|
57
|
-
.
|
|
58
|
-
.
|
|
56
|
+
.heedb-tab.active { color: ${a}; border-bottom-color: ${t}; }
|
|
57
|
+
.heedb-body { padding: 16px; overflow-y: auto; flex: 1; }
|
|
58
|
+
.heedb-label { display: block; font-size: 12px; font-weight: 600; color: #52525b; margin-bottom: 4px; }
|
|
59
|
+
.heedb-input, .heedb-textarea, .heedb-select {
|
|
59
60
|
width: 100%; box-sizing: border-box; padding: 8px 10px;
|
|
60
|
-
border: 1px solid ${
|
|
61
|
-
font-size: 13px; color: ${
|
|
62
|
-
font-family: inherit; background: ${
|
|
61
|
+
border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
|
|
62
|
+
font-size: 13px; color: ${a}; margin-bottom: 10px;
|
|
63
|
+
font-family: inherit; background: ${b?"#222":o};
|
|
63
64
|
}
|
|
64
|
-
.
|
|
65
|
-
.
|
|
65
|
+
.heedb-textarea { min-height: 80px; resize: vertical; }
|
|
66
|
+
.heedb-input:focus, .heedb-textarea:focus, .heedb-select:focus {
|
|
66
67
|
outline: none; border-color: ${t};
|
|
67
68
|
}
|
|
68
|
-
.
|
|
69
|
+
.heedb-btn-submit {
|
|
69
70
|
width: 100%; padding: 10px; background: ${t}; color: #fff;
|
|
70
|
-
border: none; border-radius: ${
|
|
71
|
+
border: none; border-radius: ${p}px; font-size: 14px; font-weight: 600;
|
|
71
72
|
cursor: pointer; transition: opacity .15s;
|
|
72
73
|
}
|
|
73
|
-
.
|
|
74
|
-
.
|
|
75
|
-
.
|
|
76
|
-
.
|
|
77
|
-
.
|
|
78
|
-
.
|
|
79
|
-
.
|
|
80
|
-
.
|
|
81
|
-
padding: 10px 12px; border: 1px solid ${
|
|
74
|
+
.heedb-btn-submit:hover { opacity: .85; }
|
|
75
|
+
.heedb-btn-submit:disabled { opacity: .5; cursor: not-allowed; }
|
|
76
|
+
.heedb-error { color: #ef4444; font-size: 12px; margin-bottom: 8px; }
|
|
77
|
+
.heedb-success { text-align: center; padding: 24px 8px; }
|
|
78
|
+
.heedb-success-icon { font-size: 36px; }
|
|
79
|
+
.heedb-success h3 { margin: 12px 0 6px; font-size: 15px; color: ${a}; }
|
|
80
|
+
.heedb-success p { margin: 0; color: #71717a; font-size: 13px; line-height: 1.5; }
|
|
81
|
+
.heedb-thread-item {
|
|
82
|
+
padding: 10px 12px; border: 1px solid ${b?"#333":"#e4e4e7"}; border-radius: ${p}px;
|
|
82
83
|
margin-bottom: 8px; cursor: pointer; display: block; color: inherit;
|
|
83
84
|
transition: background .1s; background: none;
|
|
84
85
|
}
|
|
85
|
-
.
|
|
86
|
-
.
|
|
87
|
-
.
|
|
88
|
-
.
|
|
89
|
-
.
|
|
90
|
-
.
|
|
91
|
-
.
|
|
92
|
-
.
|
|
93
|
-
.
|
|
94
|
-
width: 100%; padding: 8px; background: none; border: 1px solid ${
|
|
95
|
-
border-radius: ${
|
|
96
|
-
}
|
|
97
|
-
.
|
|
98
|
-
.
|
|
99
|
-
padding: 6px 16px; text-align: center; border-top: 1px solid ${
|
|
100
|
-
}
|
|
101
|
-
.
|
|
86
|
+
.heedb-thread-item:hover { background: ${b?"#252525":"#f4f4f5"}; }
|
|
87
|
+
.heedb-thread-label { font-size: 12px; color: #71717a; margin-bottom: 2px; }
|
|
88
|
+
.heedb-thread-text { font-size: 13px; color: ${a}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
89
|
+
.heedb-thread-meta { font-size: 11px; color: #a1a1aa; margin-top: 3px; }
|
|
90
|
+
.heedb-badge { display: inline-block; padding: 1px 6px; border-radius: 9999px; font-size: 10px; font-weight: 600; }
|
|
91
|
+
.heedb-badge-open { background: #d1fae5; color: #065f46; }
|
|
92
|
+
.heedb-badge-replied { background: #dbeafe; color: #1e40af; }
|
|
93
|
+
.heedb-new-msg { margin-top: 12px; padding-top: 12px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; }
|
|
94
|
+
.heedb-new-msg button {
|
|
95
|
+
width: 100%; padding: 8px; background: none; border: 1px solid ${b?"#444":"#d4d4d8"};
|
|
96
|
+
border-radius: ${p}px; font-size: 13px; cursor: pointer; color: ${b?"#999":"#52525b"};
|
|
97
|
+
}
|
|
98
|
+
.heedb-new-msg button:hover { background: ${b?"#252525":"#f4f4f5"}; }
|
|
99
|
+
.heedb-footer {
|
|
100
|
+
padding: 6px 16px; text-align: center; border-top: 1px solid ${b?"#333":"#f0f0f0"};
|
|
101
|
+
}
|
|
102
|
+
.heedb-footer a {
|
|
102
103
|
font-size: 10px; color: #a1a1aa; text-decoration: none; font-weight: 500;
|
|
103
104
|
}
|
|
104
|
-
.
|
|
105
|
+
.heedb-footer a:hover { color: #71717a; text-decoration: underline; }
|
|
105
106
|
|
|
106
107
|
/* Chat view */
|
|
107
|
-
.
|
|
108
|
+
.heedb-chat-back {
|
|
108
109
|
background: none; border: none; cursor: pointer; font-size: 13px;
|
|
109
110
|
color: ${t}; padding: 0; margin-bottom: 12px; font-weight: 500;
|
|
110
111
|
display: flex; align-items: center; gap: 4px;
|
|
111
112
|
}
|
|
112
|
-
.
|
|
113
|
-
.
|
|
113
|
+
.heedb-chat-back:hover { text-decoration: underline; }
|
|
114
|
+
.heedb-chat-messages {
|
|
114
115
|
display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px;
|
|
115
116
|
max-height: 320px; overflow-y: auto;
|
|
116
117
|
}
|
|
117
|
-
.
|
|
118
|
-
padding: 8px 12px; border-radius: ${Math.max(
|
|
118
|
+
.heedb-chat-bubble {
|
|
119
|
+
padding: 8px 12px; border-radius: ${Math.max(p,8)}px; font-size: 13px;
|
|
119
120
|
line-height: 1.45; max-width: 85%; word-wrap: break-word;
|
|
120
121
|
white-space: pre-wrap;
|
|
121
122
|
}
|
|
122
|
-
.
|
|
123
|
-
background: ${
|
|
123
|
+
.heedb-chat-inbound {
|
|
124
|
+
background: ${b?"#252525":"#f4f4f5"}; color: ${a}; align-self: flex-start;
|
|
124
125
|
border-bottom-left-radius: 4px;
|
|
125
126
|
}
|
|
126
|
-
.
|
|
127
|
+
.heedb-chat-outbound {
|
|
127
128
|
background: ${t}; color: #fff; align-self: flex-end;
|
|
128
129
|
border-bottom-right-radius: 4px;
|
|
129
130
|
}
|
|
130
|
-
.
|
|
131
|
+
.heedb-chat-time {
|
|
131
132
|
font-size: 10px; color: #a1a1aa; margin-top: 2px;
|
|
132
133
|
}
|
|
133
|
-
.
|
|
134
|
-
.
|
|
135
|
-
display: flex; gap: 8px; border-top: 1px solid ${
|
|
134
|
+
.heedb-chat-time-right { text-align: right; }
|
|
135
|
+
.heedb-chat-reply {
|
|
136
|
+
display: flex; gap: 8px; border-top: 1px solid ${b?"#333":"#e4e4e7"}; padding-top: 12px;
|
|
136
137
|
}
|
|
137
|
-
.
|
|
138
|
-
flex: 1; padding: 8px 10px; border: 1px solid ${
|
|
139
|
-
font-size: 13px; font-family: inherit; color: ${
|
|
138
|
+
.heedb-chat-reply-input {
|
|
139
|
+
flex: 1; padding: 8px 10px; border: 1px solid ${b?"#444":"#d4d4d8"}; border-radius: ${p}px;
|
|
140
|
+
font-size: 13px; font-family: inherit; color: ${a}; background: ${b?"#222":o};
|
|
140
141
|
resize: none; min-height: 36px; max-height: 80px; box-sizing: border-box;
|
|
141
142
|
}
|
|
142
|
-
.
|
|
143
|
-
.
|
|
143
|
+
.heedb-chat-reply-input:focus { outline: none; border-color: ${t}; }
|
|
144
|
+
.heedb-chat-send {
|
|
144
145
|
padding: 8px 14px; background: ${t}; color: #fff; border: none;
|
|
145
|
-
border-radius: ${
|
|
146
|
+
border-radius: ${p}px; font-size: 13px; font-weight: 600; cursor: pointer;
|
|
146
147
|
transition: opacity .15s; white-space: nowrap; align-self: flex-end;
|
|
147
148
|
}
|
|
148
|
-
.
|
|
149
|
-
.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
.heedb-chat-send:hover { opacity: .85; }
|
|
150
|
+
.heedb-chat-send:disabled { opacity: .5; cursor: not-allowed; }
|
|
151
|
+
|
|
152
|
+
/* Skeleton loading */
|
|
153
|
+
.heedb-skeleton { pointer-events: none; }
|
|
154
|
+
.heedb-skel-line {
|
|
155
|
+
background: ${b?"#333":"#e4e4e7"};
|
|
156
|
+
border-radius: 4px;
|
|
157
|
+
animation: heedb-pulse 1.5s ease-in-out infinite;
|
|
158
|
+
}
|
|
159
|
+
@keyframes heedb-pulse {
|
|
160
|
+
0%, 100% { opacity: 0.4; }
|
|
161
|
+
50% { opacity: 1; }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Body fade transition */
|
|
165
|
+
.heedb-body { transition: opacity .15s ease; }
|
|
166
|
+
`}function s(e,t={},a=[]){let o=document.createElement(e);for(let[i,l]of Object.entries(t))i==="class"?o.className=l:i==="style"?o.setAttribute("style",l):i.startsWith("on")&&typeof l=="function"?o.addEventListener(i.slice(2),l):o.setAttribute(i,String(l));for(let i of a)o.appendChild(typeof i=="string"?document.createTextNode(i):i);return o}function U(e,t,a=""){let o=document.createElement("input");return o.type=e,o.id=t,o.placeholder=a,o.className="heedb-input",o}function he(e,t=""){let a=document.createElement("textarea");return a.id=e,a.placeholder=t,a.className="heedb-textarea",a}function be(e,t){let a=document.createElement("select");a.id=e,a.className="heedb-select";for(let o of t){let i=document.createElement("option");i.value=o.value,i.textContent=o.label,a.appendChild(i)}return a}function C(){if(!f)return;let e=f.querySelector(".heedb-body");e.innerHTML="",E==="contact"?fe(e):E==="privacy"?xe(e):E==="threads"?ye(e):E==="thread-detail"&&Te(e),$&&($.style.display=E==="thread-detail"?"none":"flex")}function fe(e,t=""){let a=!!(P&&k),o=s("label",{class:"heedb-label"},[n("nameLabel")]),i=U("text","heedb-name",n("namePlaceholder"));P&&(i.value=P);let l=s("label",{class:"heedb-label"},[n("emailLabel")]),y=U("email","heedb-email",n("emailPlaceholder"));(t||k)&&(y.value=t||k);let h=O(r.messageLabel),c=h?s("label",{class:"heedb-label"},[h]):null,p=he("heedb-message",O(r.messagePlaceholder)||n("messagePlaceholder")),d=s("div",{class:"heedb-error",style:"display:none"}),m=s("button",{class:"heedb-btn-submit"},[n("sendMessage")]);m.onclick=async()=>{var x;let g=i.value.trim(),v=y.value.trim(),u=p.value.trim();if(d.style.display="none",!g||!v||!u){d.textContent=n("fillAllFields"),d.style.display="block";return}m.disabled=!0,m.textContent=n("sending");try{let T=await W("/api/contact",{api_key:A,name:g,email:v,message:u,lang:R});if(T.ok)k=v,localStorage.setItem("heedb_email",v),q(),Q(e,n("messageSentTitle"),n("messageSentBody"));else if(T.status===429){let w=parseInt((x=T.headers.get("Retry-After"))!=null?x:"60",10);d.textContent=n("rateLimited"),d.style.display="block",m.textContent=n("sendMessage"),setTimeout(()=>{m.disabled=!1,d.style.display="none"},w*1e3)}else{let w=await T.json();d.textContent=w.error||n("somethingWrong"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}}catch(T){d.textContent=n("networkError"),d.style.display="block",m.disabled=!1,m.textContent=n("sendMessage")}},a?(c&&e.append(c),e.append(p,d,m)):(e.append(o,i,l,y),c&&e.append(c),e.append(p,d,m))}function xe(e){let t=!!(P&&k),a=s("label",{class:"heedb-label"},[n("nameLabel")]),o=U("text","heedb-priv-name",n("namePlaceholder"));P&&(o.value=P);let i=s("label",{class:"heedb-label"},[n("emailLabel")]),l=U("email","heedb-priv-email",n("emailPlaceholder"));k&&(l.value=k);let y=s("label",{class:"heedb-label"},[n("requestType")]),h=be("heedb-priv-type",[{value:"deletion",label:n("deleteData")},{value:"access",label:n("accessData")},{value:"portability",label:n("exportData")}]),c=s("div",{class:"heedb-error",style:"display:none"}),p=s("button",{class:"heedb-btn-submit"},[n("submitRequest")]);p.onclick=async()=>{var v;let d=o.value.trim(),m=l.value.trim(),g=h.value;if(c.style.display="none",!d||!m){c.textContent=n("fillAllFields"),c.style.display="block";return}p.disabled=!0,p.textContent=n("submitting");try{let u=await W("/api/privacy-request",{api_key:A,name:d,email:m,request_type:g,lang:R});if(u.ok)k=m,localStorage.setItem("heedb_email",m),q(),Q(e,n("requestSubmittedTitle"),n("requestSubmittedBody"));else if(u.status===429){let x=parseInt((v=u.headers.get("Retry-After"))!=null?v:"60",10);c.textContent=n("rateLimited"),c.style.display="block",p.textContent=n("submitRequest"),setTimeout(()=>{p.disabled=!1,c.style.display="none"},x*1e3)}else{let x=await u.json();c.textContent=x.error||n("somethingWrong"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}}catch(u){c.textContent=n("networkError"),c.style.display="block",p.disabled=!1,p.textContent=n("submitRequest")}},t?e.append(y,h,c,p):e.append(a,o,i,l,y,h,c,p)}async function ye(e){var t;if(!M){e.innerHTML="";let a=s("p",{style:"color:#71717a;text-align:center;margin:8px 0;font-size:13px;line-height:1.5"},[n("noThreadsAuth")]),o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendAMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.append(a,o);return}e.innerHTML="";for(let a=0;a<3;a++){let o=s("div",{class:"heedb-thread-item heedb-skeleton"});o.append(s("div",{class:"heedb-skel-line",style:"width:40%;height:12px"}),s("div",{class:"heedb-skel-line",style:"width:80%;height:13px;margin-top:6px"}),s("div",{class:"heedb-skel-line",style:"width:30%;height:11px;margin-top:4px"})),e.appendChild(o)}try{let{threads:a}=await pe(k);if(e.innerHTML="",e.style.opacity="0",requestAnimationFrame(()=>{e.style.opacity="1"}),a.length===0){let l=s("p",{style:"color:#71717a;text-align:center;margin:8px 0"},[O(r.emptyStateText)||n("noOpenMessages")]);e.appendChild(l)}else for(let l of a){let y=s("span",{class:`heedb-badge heedb-badge-${l.status}`},[l.status]),h=s("div",{class:"heedb-thread-label"},[l.type==="privacy"?n("privacyRequest"):n("message")," \u2022 "]);h.appendChild(y);let c=s("div",{class:"heedb-thread-text"},[(t=l.preview)!=null?t:""]),p=new Date(l.createdAt).toLocaleDateString(),d=s("div",{class:"heedb-thread-meta"},[p]),m=s("div",{class:"heedb-thread-item"});m.append(h,c,d),m.onclick=()=>ve(l.id),e.appendChild(m)}let o=s("div",{class:"heedb-new-msg"}),i=s("button",{},[n("sendNewMessage")]);i.onclick=()=>{E="contact",B("contact"),C()},o.appendChild(i),e.appendChild(o)}catch(a){e.innerHTML=`<p style="color:#ef4444;text-align:center">${n("failedToLoad")}</p>`}}function ve(e){K=e,E="thread-detail",C()}async function Te(e){e.innerHTML="",e.style.padding="12px";let t=s("div",{class:"heedb-skel-line",style:"width:50%;height:13px;margin-bottom:12px"});e.appendChild(t);let a=s("div",{style:"display:flex;flex-direction:column;gap:8px"}),o=["65%","50%","70%","45%"],i=["flex-start","flex-end","flex-start","flex-end"];for(let y=0;y<4;y++){let h=s("div",{style:`display:flex;flex-direction:column;align-items:${i[y]}`});h.appendChild(s("div",{class:"heedb-skel-line",style:`width:${o[y]};height:32px;border-radius:8px`})),a.appendChild(h)}e.appendChild(a);let l=s("button",{class:"heedb-chat-back"},[n("backToMessages")]);l.onclick=()=>{E="threads",B("threads"),C()};try{let h=(await me(K)).messages||[];e.innerHTML="",e.style.padding="12px",e.appendChild(l);let c=s("div",{class:"heedb-chat-messages"});for(let u of h){let x=u.direction==="inbound",T=s("div",{style:`display:flex;flex-direction:column;${x?"align-items:flex-start":"align-items:flex-end"}`}),w=s("div",{class:`heedb-chat-bubble ${x?"heedb-chat-inbound":"heedb-chat-outbound"}`},[we(u.body)]),H=s("div",{class:`heedb-chat-time ${x?"":"heedb-chat-time-right"}`},[ke(u.createdAt)]);T.append(w,H),c.appendChild(T)}e.appendChild(c),requestAnimationFrame(()=>{c.scrollTop=c.scrollHeight});let p=s("div",{class:"heedb-chat-reply"}),d=document.createElement("textarea");d.className="heedb-chat-reply-input",d.placeholder=n("typeReply"),d.rows=1,d.addEventListener("input",()=>{d.style.height="auto",d.style.height=Math.min(d.scrollHeight,80)+"px"});let m=s("button",{class:"heedb-chat-send"},[n("send")]),g=s("div",{class:"heedb-error",style:"display:none;margin-top:4px"});async function v(){let u=d.value.trim();if(u){m.disabled=!0,m.textContent="\u2026",g.style.display="none";try{let x=await ge(K,u);if(x.ok){let T=s("div",{style:"display:flex;flex-direction:column;align-items:flex-start"}),w=s("div",{class:"heedb-chat-bubble heedb-chat-inbound"},[u]),H=s("div",{class:"heedb-chat-time"},[n("justNow")]);T.append(w,H),c.appendChild(T),c.scrollTop=c.scrollHeight,d.value="",d.style.height="auto"}else{let T=await x.json();g.textContent=T.error||n("failedToSend"),g.style.display="block"}}catch(x){g.textContent=n("networkError"),g.style.display="block"}m.disabled=!1,m.textContent=n("send")}}m.onclick=v,d.addEventListener("keydown",u=>{u.key==="Enter"&&!u.shiftKey&&(u.preventDefault(),v())}),p.append(d,m),e.append(p,g),requestAnimationFrame(()=>d.focus())}catch(y){e.innerHTML="",e.appendChild(l),e.appendChild(s("p",{style:"color:#ef4444;text-align:center"},[n("failedToLoadConvo")]))}}function we(e){let t=e.split(`
|
|
167
|
+
`),a=[];for(let o of t){let i=o.trim();if(/^(On|Em|El|Le|Am|Il giorno) .+(<[^>]+@[^>]+>).*(wrote|escreveu|escribi|crit|schrieb|scritto)\s?:$/i.test(i)||/<[^>]+@[^>]+>/.test(i)&&i.endsWith(":")||/^-{3,}$/.test(i))break;/^>{1,}\s/.test(i)||a.push(o)}return a.join(`
|
|
168
|
+
`).trim()}function ke(e){let t=new Date(e),o=new Date().getTime()-t.getTime(),i=Math.floor(o/6e4);if(i<1)return n("justNow");if(i<60)return n("minutesAgo").replace("{mins}",String(i));let l=Math.floor(i/60);return l<24?n("hoursAgo").replace("{hours}",String(l)):t.toLocaleDateString()}function Q(e,t,a){e.innerHTML="";let o=s("div",{class:"heedb-success"});o.innerHTML=`
|
|
169
|
+
<div class="heedb-success-icon">\u2705</div>
|
|
154
170
|
<h3>${t}</h3>
|
|
155
|
-
<p>${
|
|
156
|
-
`,e.appendChild(
|
|
171
|
+
<p>${a}</p>
|
|
172
|
+
`,e.appendChild(o)}let $=null,D=null;function B(e){E=e,$&&$.querySelectorAll(".heedb-tab").forEach(t=>{t.classList.toggle("active",t.dataset.mode===e)})}function q(){D&&(D.style.display=k&&M?"":"none")}let I=null;function Z(){b=J(),I&&(I.textContent=X())}async function ee(){if(r=await ue(),R=G(),b=J(),I=document.createElement("style"),I.textContent=X(),document.head.appendChild(I),r.customCSS){let g=document.createElement("style");g.textContent=r.customCSS,document.head.appendChild(g)}r.mode==="system"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{Z(),S&&f&&C()});let e=r.triggerIcon?r.triggerIcon:r.triggerEmoji||"\u{1F4AC}",t=r.triggerText||"";if(_=s("button",{class:"heedb-btn",title:n("contactUs"),"aria-label":"Open contact widget"}),r.triggerIcon){let g=s("span",{class:"heedb-btn-icon"}),u=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(u){u.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(w=>w.remove());let x=document.createTreeWalker(u,NodeFilter.SHOW_ELEMENT),T;for(;T=x.nextNode();)for(let w of Array.from(T.attributes))(w.name.startsWith("on")||/^\s*javascript:/i.test(w.value))&&T.removeAttribute(w.name);g.appendChild(u)}_.appendChild(g)}else _.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));if(t&&_.appendChild(s("span",{class:"heedb-btn-label"},[t])),_.onclick=V,document.body.appendChild(_),r.triggerMode==="embedded"&&r.triggerSelector){let g=document.querySelector(r.triggerSelector);g&&g.addEventListener("click",v=>{v.preventDefault(),V()})}if(r.triggerMode==="tag"){let g=s("button",{class:"heedb-tag","aria-label":"Open contact widget"}),v=s("span",{class:"heedb-tag-icon"});if(r.triggerIcon){let x=new DOMParser().parseFromString(r.triggerIcon,"image/svg+xml").querySelector("svg");if(x){x.querySelectorAll("script,foreignObject,iframe,object,embed").forEach(H=>H.remove());let T=document.createTreeWalker(x,NodeFilter.SHOW_ELEMENT),w;for(;w=T.nextNode();)for(let H of Array.from(w.attributes))(H.name.startsWith("on")||/^\s*javascript:/i.test(H.value))&&w.removeAttribute(H.name);v.appendChild(x)}}else v.appendChild(document.createTextNode(r.triggerEmoji||"\u{1F4AC}"));g.appendChild(v),g.appendChild(document.createTextNode(r.triggerText||n("feedback"))),g.onclick=V,document.body.appendChild(g)}f=s("div",{class:"heedb-panel",style:"display:none"});let a=s("div",{class:"heedb-header"}),o=s("h2",{},[r.headerTitle||n("contactUs")]),i=s("button",{class:"heedb-close","aria-label":"Close"},["\u2715"]);i.onclick=V,a.append(o,i),$=s("div",{class:"heedb-tabs"});let l=s("button",{class:"heedb-tab active","data-mode":"contact"},[O(r.contactTabLabel)||n("contactTab")]),h=r.showPrivacyTab!==!1?s("button",{class:"heedb-tab","data-mode":"privacy"},[n("privacyTab")]):null;D=s("button",{class:"heedb-tab","data-mode":"threads"},[n("messagesTab")]),D.style.display=k&&M?"":"none",l.onclick=()=>{B("contact"),C()},h&&(h.onclick=()=>{B("privacy"),C()}),D.onclick=()=>{B("threads"),C()},$.append(l),h&&$.append(h),$.append(D);let c=s("div",{class:"heedb-body"}),p=s("div",{class:"heedb-footer"}),d=new URLSearchParams({utm_source:"widget",utm_medium:"heedb-widget",utm_campaign:window.location.hostname}),m=s("a",{href:`https://heedb.com?${d.toString()}`,target:"_blank",rel:"noopener noreferrer"},[n("poweredBy")]);p.appendChild(m),f.append(a,$,c,p),document.body.appendChild(f)}function V(){S=!S,f&&(S?(f.style.display="flex",f.style.opacity="0",f.style.transform="translateY(8px)",requestAnimationFrame(()=>{f.style.opacity="1",f.style.transform="translateY(0)"}),k&&M&&E!=="privacy"&&E!=="thread-detail"&&(E="threads",B("threads")),C()):(f.style.opacity="0",f.style.transform="translateY(8px)",setTimeout(()=>{!S&&f&&(f.style.display="none")},150)))}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ee):ee()})();})();
|