@sendystack/widget 0.1.2 → 0.1.4
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/dist/index.es.js +131 -84
- package/dist/widget.global.js +27 -13
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/index.ts
|
|
2
|
-
var e = "sendystack-widget-root",
|
|
3
|
-
async function
|
|
2
|
+
var e = "https://app.sendystack.org/sendy_stack_favico.png", t = "sendystack-widget-root", n = (e) => `sendystack_sessions_${e}`, r = (e) => `sendystack_current_${e}`, i = (e) => `sendystack_crawled_${e}`, a = "<svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M6 6l12 12M18 6L6 18\"/></svg>", o = "<svg viewBox=\"0 0 24 24\" width=\"19\" height=\"19\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 12l16-7-7 16-2-7-7-2z\"/></svg>", s = "<svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M12 7v5l3 3\"/></svg>", c = "<svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 5v14M5 12h14\"/></svg>", l = "<svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 18l-6-6 6-6\"/></svg>";
|
|
3
|
+
async function u(e, t) {
|
|
4
4
|
let n = await (await fetch(`${e}/embedConfig?embedToken=${encodeURIComponent(t)}`)).json();
|
|
5
5
|
if (!n.ok) throw Error(n.error || "failed to load widget config");
|
|
6
6
|
return {
|
|
@@ -8,37 +8,39 @@ async function d(e, t) {
|
|
|
8
8
|
whiteLabel: !!n.whiteLabel
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
let n =
|
|
11
|
+
function d(e) {
|
|
12
|
+
let n = e.position === "left" ? "left" : "right", r = document.createElement("style");
|
|
13
13
|
r.textContent = `
|
|
14
|
-
#${
|
|
15
|
-
#${
|
|
16
|
-
.ssk-launcher{position:relative;width:60px;height:60px;border-radius:50%;border:none;cursor:pointer;color
|
|
17
|
-
background
|
|
14
|
+
#${t} *{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}
|
|
15
|
+
#${t}{position:fixed;${n}:20px;bottom:20px;z-index:2147483000;}
|
|
16
|
+
.ssk-launcher{position:relative;width:60px;height:60px;border-radius:50%;border:none;cursor:pointer;color:${e.accent};
|
|
17
|
+
background:#fff;box-shadow:0 16px 36px rgba(0,0,0,.22),0 0 0 1px rgba(27,39,51,.05);
|
|
18
18
|
display:flex;align-items:center;justify-content:center;transition:transform .25s cubic-bezier(.16,1,.3,1);margin-left:auto;}
|
|
19
19
|
.ssk-launcher:hover{transform:translateY(-3px) scale(1.04);}
|
|
20
20
|
.ssk-launcher:active{transform:scale(.96);}
|
|
21
21
|
.ssk-launcher .ssk-open{display:flex;} .ssk-launcher .ssk-x{display:none;}
|
|
22
|
-
|
|
23
|
-
.ssk-
|
|
22
|
+
.ssk-launcher .ssk-open img{width:32px;height:32px;object-fit:contain;}
|
|
23
|
+
#${t}.open .ssk-launcher .ssk-open{display:none;} #${t}.open .ssk-launcher .ssk-x{display:flex;}
|
|
24
|
+
.ssk-pulse{position:absolute;inset:0;border-radius:50%;background:${e.accent};opacity:.5;z-index:-1;animation:sskPulse 2.4s ease-out infinite;}
|
|
24
25
|
@keyframes sskPulse{0%{transform:scale(1);opacity:.5;}70%,100%{transform:scale(1.7);opacity:0;}}
|
|
25
26
|
@media(prefers-reduced-motion:reduce){.ssk-pulse{animation:none;}}
|
|
26
|
-
.ssk-greeting{position:absolute;bottom:72px;${n}:0;max-width:
|
|
27
|
+
.ssk-greeting{position:absolute;bottom:72px;${n}:0;width:max-content;max-width:min(300px,calc(100vw - 48px));padding:11px 16px;border-radius:14px;background:#fff;
|
|
27
28
|
color:#1b2733;font-size:13.5px;line-height:1.4;font-weight:600;box-shadow:0 16px 38px rgba(27,39,51,.18);
|
|
28
29
|
transform:translateY(8px);opacity:0;pointer-events:none;transition:opacity .3s,transform .3s;}
|
|
29
30
|
.ssk-greeting.shown{opacity:1;transform:translateY(0);}
|
|
30
|
-
#${
|
|
31
|
+
#${t}.open .ssk-greeting{display:none;}
|
|
31
32
|
.ssk-panel{position:absolute;bottom:74px;${n}:0;width:368px;max-width:calc(100vw - 32px);height:560px;
|
|
32
33
|
max-height:calc(100vh - 110px);background:#fff;border-radius:20px;overflow:hidden;display:flex;flex-direction:column;
|
|
33
34
|
box-shadow:0 36px 80px rgba(20,20,30,.3);border:1px solid rgba(27,39,51,.08);
|
|
34
35
|
transform:translateY(14px) scale(.96);opacity:0;pointer-events:none;transform-origin:bottom ${n};
|
|
35
36
|
transition:transform .25s cubic-bezier(.16,1,.3,1),opacity .2s;}
|
|
36
|
-
#${
|
|
37
|
+
#${t}.open .ssk-panel{transform:translateY(0) scale(1);opacity:1;pointer-events:auto;}
|
|
37
38
|
.ssk-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:13px 14px;flex-shrink:0;
|
|
38
|
-
background:linear-gradient(135deg,${
|
|
39
|
+
background:linear-gradient(135deg,${e.accent2},${e.accent});color:#fff;}
|
|
39
40
|
.ssk-id{display:flex;align-items:center;gap:9px;min-width:0;}
|
|
40
41
|
.ssk-avatar{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;
|
|
41
|
-
background
|
|
42
|
+
background:#fff;flex:0 0 auto;}
|
|
43
|
+
.ssk-avatar img{width:22px;height:22px;object-fit:contain;}
|
|
42
44
|
.ssk-id-text{min-width:0;}
|
|
43
45
|
.ssk-id-text strong{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
44
46
|
.ssk-status{display:flex;align-items:center;gap:5px;font-size:11px;opacity:.9;}
|
|
@@ -65,29 +67,41 @@ function f(t) {
|
|
|
65
67
|
.ssk-history-item.active{background:rgba(226,112,15,.1);}
|
|
66
68
|
.ssk-history-title{display:block;font-size:13.5px;font-weight:600;color:#1b2733;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
67
69
|
.ssk-history-time{display:block;font-size:11px;color:#9aa3ad;margin-top:2px;}
|
|
68
|
-
.ssk-msg{display:flex;max-width:86%;}
|
|
69
|
-
.ssk-msg.bot{align-self:flex-start;} .ssk-msg.user{align-self:flex-end;}
|
|
70
|
+
.ssk-msg{display:flex;flex-direction:column;align-items:flex-start;max-width:86%;}
|
|
71
|
+
.ssk-msg.bot{align-self:flex-start;} .ssk-msg.user{align-self:flex-end;align-items:flex-end;}
|
|
70
72
|
.ssk-bubble-text{padding:10px 13px;border-radius:15px;font-size:14px;line-height:1.5;word-wrap:break-word;}
|
|
71
73
|
.ssk-msg.bot .ssk-bubble-text{background:#fff;border:1px solid rgba(27,39,51,.08);border-bottom-left-radius:5px;
|
|
72
74
|
box-shadow:0 5px 14px rgba(27,39,51,.05);color:#1b2733;}
|
|
73
|
-
.ssk-msg.user .ssk-bubble-text{background:linear-gradient(135deg,${
|
|
74
|
-
.ssk-bubble-text a{color:${
|
|
75
|
+
.ssk-msg.user .ssk-bubble-text{background:linear-gradient(135deg,${e.accent2},${e.accent});color:#fff;border-bottom-right-radius:5px;}
|
|
76
|
+
.ssk-bubble-text a{color:${e.accent};font-weight:700;text-decoration:underline;}
|
|
75
77
|
.ssk-msg.user .ssk-bubble-text a{color:#fff;}
|
|
76
78
|
.ssk-bubble-text p{margin:0 0 7px;} .ssk-bubble-text p:last-child{margin:0;}
|
|
79
|
+
.ssk-sources{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px;}
|
|
80
|
+
.ssk-source-pill{display:inline-flex;align-items:center;padding:5px 11px;border-radius:999px;
|
|
81
|
+
background:rgba(27,39,51,.05);color:${e.accent};font-size:12px;font-weight:600;
|
|
82
|
+
text-decoration:none;border:1px solid rgba(27,39,51,.08);}
|
|
83
|
+
.ssk-source-pill:hover{background:rgba(27,39,51,.08);}
|
|
84
|
+
.ssk-action-btn{margin-top:7px;border:none;border-radius:12px;padding:9px 15px;font-size:13px;font-weight:700;
|
|
85
|
+
cursor:pointer;color:#fff;background:linear-gradient(135deg,${e.accent2},${e.accent});
|
|
86
|
+
box-shadow:0 6px 16px rgba(0,0,0,.15);transition:transform .15s;}
|
|
87
|
+
.ssk-action-btn:hover{transform:translateY(-1px);}
|
|
88
|
+
.ssk-action-btn:disabled{cursor:default;transform:none;}
|
|
89
|
+
.ssk-action-btn.ssk-action-done{opacity:.75;}
|
|
90
|
+
.ssk-action-btn.ssk-action-missing{background:rgba(27,39,51,.08);color:#6b7280;box-shadow:none;}
|
|
77
91
|
.ssk-typing{padding:0 14px 10px;flex-shrink:0;}
|
|
78
92
|
.ssk-typing[hidden]{display:none;}
|
|
79
93
|
.ssk-dots{display:inline-flex;gap:5px;padding:10px 13px;background:#fff;border:1px solid rgba(27,39,51,.08);
|
|
80
94
|
border-radius:15px;border-bottom-left-radius:5px;}
|
|
81
|
-
.ssk-dots i{width:7px;height:7px;border-radius:50%;background:${
|
|
95
|
+
.ssk-dots i{width:7px;height:7px;border-radius:50%;background:${e.accent};animation:sskWave 1.2s ease-in-out infinite;}
|
|
82
96
|
.ssk-dots i:nth-child(2){animation-delay:.15s;} .ssk-dots i:nth-child(3){animation-delay:.3s;}
|
|
83
97
|
@keyframes sskWave{0%,60%,100%{transform:translateY(0);opacity:.5;}30%{transform:translateY(-5px);opacity:1;}}
|
|
84
98
|
.ssk-inputrow{display:flex;align-items:flex-end;gap:8px;padding:11px;border-top:1px solid rgba(27,39,51,.08);
|
|
85
99
|
background:#fff;flex-shrink:0;}
|
|
86
100
|
.ssk-inputrow textarea{flex:1;resize:none;max-height:90px;border:1px solid rgba(27,39,51,.14);border-radius:13px;
|
|
87
101
|
padding:10px 12px;font-size:14px;line-height:1.4;color:#1b2733;outline:none;background:#fbf7f1;}
|
|
88
|
-
.ssk-inputrow textarea:focus{border-color:${
|
|
102
|
+
.ssk-inputrow textarea:focus{border-color:${e.accent};background:#fff;}
|
|
89
103
|
.ssk-sendbtn{width:42px;height:42px;flex:0 0 auto;border:none;border-radius:12px;cursor:pointer;color:#fff;
|
|
90
|
-
background:linear-gradient(135deg,${
|
|
104
|
+
background:linear-gradient(135deg,${e.accent2},${e.accent});display:flex;align-items:center;justify-content:center;
|
|
91
105
|
box-shadow:0 9px 20px rgba(0,0,0,.18);transition:transform .15s;}
|
|
92
106
|
.ssk-sendbtn:hover{transform:translateY(-2px);}
|
|
93
107
|
.ssk-sendbtn:disabled{opacity:.6;cursor:default;transform:none;}
|
|
@@ -95,47 +109,78 @@ function f(t) {
|
|
|
95
109
|
.ssk-foot a{color:inherit;text-decoration:underline;}
|
|
96
110
|
`, document.head.appendChild(r);
|
|
97
111
|
}
|
|
98
|
-
function
|
|
112
|
+
function f(e) {
|
|
99
113
|
return `<p>${e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, "<a href=\"$2\" target=\"_blank\" rel=\"noopener\">$1</a>").replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>").replace(/\n{2,}/g, "</p><p>").replace(/\n/g, "<br>")}</p>`;
|
|
100
114
|
}
|
|
115
|
+
function p(e) {
|
|
116
|
+
let t = document.createElement("button");
|
|
117
|
+
t.type = "button", t.className = "ssk-action-btn", t.textContent = e.label;
|
|
118
|
+
let n = !e.confirmRequired;
|
|
119
|
+
return t.onclick = () => {
|
|
120
|
+
let r = e.selector ? document.querySelector(e.selector) : null;
|
|
121
|
+
if (!r) {
|
|
122
|
+
if (e.fallbackUrl) {
|
|
123
|
+
location.href = e.fallbackUrl;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
t.textContent = "Couldn't find that on this page", t.classList.add("ssk-action-missing"), t.disabled = !0;
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (!n) {
|
|
130
|
+
n = !0, t.textContent = `Click to confirm: ${e.label}`;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
r.click(), t.textContent = "Done ✓", t.disabled = !0, t.classList.add("ssk-action-done");
|
|
134
|
+
}, t;
|
|
135
|
+
}
|
|
101
136
|
function m(e, t) {
|
|
102
137
|
let n = document.createElement("div");
|
|
103
138
|
n.className = `ssk-msg ${t.role}`;
|
|
104
139
|
let r = document.createElement("div");
|
|
105
|
-
r.className = "ssk-bubble-text", r.innerHTML =
|
|
140
|
+
if (r.className = "ssk-bubble-text", r.innerHTML = f(t.text), n.appendChild(r), t.sources?.length) {
|
|
141
|
+
let e = document.createElement("div");
|
|
142
|
+
e.className = "ssk-sources";
|
|
143
|
+
for (let n of t.sources) {
|
|
144
|
+
let t = document.createElement("a");
|
|
145
|
+
t.className = "ssk-source-pill", t.href = n.url, t.textContent = n.title || n.url, e.appendChild(t);
|
|
146
|
+
}
|
|
147
|
+
n.appendChild(e);
|
|
148
|
+
}
|
|
149
|
+
for (let e of t.actions || []) n.appendChild(p(e));
|
|
150
|
+
e.appendChild(n), e.scrollTop = e.scrollHeight;
|
|
106
151
|
}
|
|
107
|
-
function
|
|
152
|
+
function h(e) {
|
|
108
153
|
try {
|
|
109
|
-
return JSON.parse(localStorage.getItem(
|
|
154
|
+
return JSON.parse(localStorage.getItem(n(e)) || "[]");
|
|
110
155
|
} catch {
|
|
111
156
|
return [];
|
|
112
157
|
}
|
|
113
158
|
}
|
|
114
|
-
function
|
|
159
|
+
function g(e, t) {
|
|
115
160
|
try {
|
|
116
|
-
localStorage.setItem(
|
|
161
|
+
localStorage.setItem(n(e), JSON.stringify(t.slice(0, 40)));
|
|
117
162
|
} catch {}
|
|
118
163
|
}
|
|
119
|
-
function
|
|
164
|
+
function _(e) {
|
|
120
165
|
try {
|
|
121
|
-
return localStorage.getItem(
|
|
166
|
+
return localStorage.getItem(r(e));
|
|
122
167
|
} catch {
|
|
123
168
|
return null;
|
|
124
169
|
}
|
|
125
170
|
}
|
|
126
|
-
function
|
|
171
|
+
function v(e, t) {
|
|
127
172
|
try {
|
|
128
|
-
localStorage.setItem(
|
|
173
|
+
localStorage.setItem(r(e), t);
|
|
129
174
|
} catch {}
|
|
130
175
|
}
|
|
131
|
-
function
|
|
176
|
+
function y() {
|
|
132
177
|
return `s_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
133
178
|
}
|
|
134
|
-
function
|
|
179
|
+
function b(e) {
|
|
135
180
|
let t = e.find((e) => e.role === "user");
|
|
136
181
|
return t ? t.text.slice(0, 60) : "New conversation";
|
|
137
182
|
}
|
|
138
|
-
function
|
|
183
|
+
function x(e) {
|
|
139
184
|
let t = new Date(e), n = /* @__PURE__ */ new Date();
|
|
140
185
|
return t.toDateString() === n.toDateString() ? t.toLocaleTimeString(void 0, {
|
|
141
186
|
hour: "numeric",
|
|
@@ -145,17 +190,17 @@ function te(e) {
|
|
|
145
190
|
day: "numeric"
|
|
146
191
|
});
|
|
147
192
|
}
|
|
148
|
-
function
|
|
149
|
-
let
|
|
150
|
-
|
|
151
|
-
let n = (
|
|
193
|
+
function S() {
|
|
194
|
+
let e = document.body.cloneNode(!0);
|
|
195
|
+
e.querySelectorAll(`script,style,nav,header,footer,svg,noscript,#${t}`).forEach((e) => e.remove());
|
|
196
|
+
let n = (e.textContent || "").replace(/\s+/g, " ").trim();
|
|
152
197
|
return {
|
|
153
198
|
title: document.title,
|
|
154
199
|
text: n
|
|
155
200
|
};
|
|
156
201
|
}
|
|
157
|
-
async function
|
|
158
|
-
let { title: n, text: r } =
|
|
202
|
+
async function C(e, t) {
|
|
203
|
+
let { title: n, text: r } = S();
|
|
159
204
|
r.length < 40 || await fetch(`${e}/ingest`, {
|
|
160
205
|
method: "POST",
|
|
161
206
|
headers: { "Content-Type": "application/json" },
|
|
@@ -169,10 +214,10 @@ async function x(e, t) {
|
|
|
169
214
|
})
|
|
170
215
|
}).catch(() => {});
|
|
171
216
|
}
|
|
172
|
-
async function
|
|
217
|
+
async function ee(e, t) {
|
|
173
218
|
let n = !1;
|
|
174
219
|
try {
|
|
175
|
-
n = !!sessionStorage.getItem(
|
|
220
|
+
n = !!sessionStorage.getItem(i(t)), sessionStorage.setItem(i(t), "1");
|
|
176
221
|
} catch {}
|
|
177
222
|
n || await fetch(`${e}/crawlSite`, {
|
|
178
223
|
method: "POST",
|
|
@@ -180,51 +225,51 @@ async function S(e, t) {
|
|
|
180
225
|
body: JSON.stringify({ embedToken: t })
|
|
181
226
|
}).catch(() => {});
|
|
182
227
|
}
|
|
183
|
-
async function
|
|
184
|
-
if (typeof document > "u" || document.getElementById(
|
|
185
|
-
let
|
|
186
|
-
if (!
|
|
228
|
+
async function w(n) {
|
|
229
|
+
if (typeof document > "u" || document.getElementById(t)) return;
|
|
230
|
+
let r = (n.token || "").trim();
|
|
231
|
+
if (!r) {
|
|
187
232
|
console.error("[Sendystack] init() called without a token");
|
|
188
233
|
return;
|
|
189
234
|
}
|
|
190
|
-
let
|
|
235
|
+
let i = n.apiBase || "https://us-central1-sendystack-fab32.cloudfunctions.net", f;
|
|
191
236
|
try {
|
|
192
|
-
|
|
237
|
+
f = await u(i, r);
|
|
193
238
|
} catch (e) {
|
|
194
239
|
console.error("[Sendystack] failed to load widget config:", e);
|
|
195
240
|
return;
|
|
196
241
|
}
|
|
197
|
-
f
|
|
198
|
-
let
|
|
199
|
-
|
|
200
|
-
let
|
|
242
|
+
d(f);
|
|
243
|
+
let p = document.createElement("div");
|
|
244
|
+
p.id = t;
|
|
245
|
+
let S = h(r), w = S.length === 0, T = _(r), E = S.find((e) => e.id === T);
|
|
201
246
|
E || (E = {
|
|
202
|
-
id:
|
|
247
|
+
id: y(),
|
|
203
248
|
title: "New conversation",
|
|
204
249
|
messages: [],
|
|
205
250
|
updatedAt: Date.now()
|
|
206
|
-
},
|
|
251
|
+
}, S.unshift(E), T = E.id, v(r, T), g(r, S));
|
|
207
252
|
let D = document.createElement("div");
|
|
208
253
|
D.className = "ssk-body";
|
|
209
254
|
function O() {
|
|
210
255
|
D.innerHTML = "";
|
|
211
256
|
let e = E.messages.length ? E.messages : [{
|
|
212
257
|
role: "bot",
|
|
213
|
-
text:
|
|
258
|
+
text: f.welcomeMessage
|
|
214
259
|
}];
|
|
215
260
|
for (let t of e) m(D, t);
|
|
216
261
|
}
|
|
217
262
|
O();
|
|
218
263
|
let k = document.createElement("span");
|
|
219
|
-
k.className = "ssk-avatar", k.innerHTML =
|
|
264
|
+
k.className = "ssk-avatar", k.innerHTML = `<img src="${e}" alt="" />`;
|
|
220
265
|
let A = document.createElement("div");
|
|
221
|
-
A.className = "ssk-id-text", A.innerHTML = `<strong>${
|
|
266
|
+
A.className = "ssk-id-text", A.innerHTML = `<strong>${f.assistantName}</strong><span class="ssk-status"><span class="ssk-dot"></span>Online</span>`;
|
|
222
267
|
let j = document.createElement("div");
|
|
223
268
|
j.className = "ssk-id", j.append(k, A);
|
|
224
269
|
let M = document.createElement("button");
|
|
225
|
-
M.className = "ssk-iconbtn", M.innerHTML =
|
|
270
|
+
M.className = "ssk-iconbtn", M.innerHTML = s, M.setAttribute("aria-label", "Chat history");
|
|
226
271
|
let N = document.createElement("button");
|
|
227
|
-
N.className = "ssk-iconbtn", N.innerHTML =
|
|
272
|
+
N.className = "ssk-iconbtn", N.innerHTML = c, N.setAttribute("aria-label", "New chat");
|
|
228
273
|
let P = document.createElement("button");
|
|
229
274
|
P.className = "ssk-closebtn", P.innerHTML = a, P.setAttribute("aria-label", "Close chat");
|
|
230
275
|
let F = document.createElement("div");
|
|
@@ -232,7 +277,7 @@ async function C(t) {
|
|
|
232
277
|
let I = document.createElement("div");
|
|
233
278
|
I.className = "ssk-head", I.append(j, F);
|
|
234
279
|
let L = document.createElement("button");
|
|
235
|
-
L.className = "ssk-history-back", L.innerHTML =
|
|
280
|
+
L.className = "ssk-history-back", L.innerHTML = l, L.setAttribute("aria-label", "Back to chat");
|
|
236
281
|
let R = document.createElement("h4");
|
|
237
282
|
R.textContent = "Chat history";
|
|
238
283
|
let z = document.createElement("div");
|
|
@@ -242,15 +287,15 @@ async function C(t) {
|
|
|
242
287
|
let V = document.createElement("div");
|
|
243
288
|
V.className = "ssk-history", V.append(z, B);
|
|
244
289
|
function H() {
|
|
245
|
-
if (B.innerHTML = "", !
|
|
290
|
+
if (B.innerHTML = "", !S.length) {
|
|
246
291
|
let e = document.createElement("div");
|
|
247
292
|
e.className = "ssk-history-empty", e.textContent = "No past conversations yet.", B.appendChild(e);
|
|
248
293
|
return;
|
|
249
294
|
}
|
|
250
|
-
for (let e of
|
|
295
|
+
for (let e of S) {
|
|
251
296
|
let t = document.createElement("button");
|
|
252
|
-
t.className = `ssk-history-item${e.id === T ? " active" : ""}`, t.innerHTML = `<span class="ssk-history-title">${e.title}</span><span class="ssk-history-time">${
|
|
253
|
-
E = e, T = e.id,
|
|
297
|
+
t.className = `ssk-history-item${e.id === T ? " active" : ""}`, t.innerHTML = `<span class="ssk-history-title">${e.title}</span><span class="ssk-history-time">${x(e.updatedAt)}</span>`, t.onclick = () => {
|
|
298
|
+
E = e, T = e.id, v(r, T), O(), H(), V.classList.remove("shown");
|
|
254
299
|
}, B.appendChild(t);
|
|
255
300
|
}
|
|
256
301
|
}
|
|
@@ -258,11 +303,11 @@ async function C(t) {
|
|
|
258
303
|
H(), V.classList.add("shown");
|
|
259
304
|
}, L.onclick = () => V.classList.remove("shown"), N.onclick = () => {
|
|
260
305
|
E.messages.length && (E = {
|
|
261
|
-
id:
|
|
306
|
+
id: y(),
|
|
262
307
|
title: "New conversation",
|
|
263
308
|
messages: [],
|
|
264
309
|
updatedAt: Date.now()
|
|
265
|
-
},
|
|
310
|
+
}, S.unshift(E), T = E.id, v(r, T), g(r, S), O(), V.classList.remove("shown"));
|
|
266
311
|
};
|
|
267
312
|
let U = document.createElement("div");
|
|
268
313
|
U.className = "ssk-typing", U.hidden = !0, U.innerHTML = "<span class=\"ssk-dots\"><i></i><i></i><i></i></span>";
|
|
@@ -273,22 +318,22 @@ async function C(t) {
|
|
|
273
318
|
let K = document.createElement("div");
|
|
274
319
|
K.className = "ssk-inputrow", K.append(W, G);
|
|
275
320
|
let q = document.createElement("div");
|
|
276
|
-
q.className = "ssk-foot", q.textContent =
|
|
321
|
+
q.className = "ssk-foot", q.textContent = f.whiteLabel ? "AI can make mistakes — confirm important details." : "AI can make mistakes — confirm important details. · Powered by Sendystack";
|
|
277
322
|
let J = document.createElement("div");
|
|
278
323
|
J.className = "ssk-panel", J.append(I, D, U, K, q, V);
|
|
279
324
|
let Y = document.createElement("button");
|
|
280
|
-
Y.className = "ssk-launcher", Y.setAttribute("aria-label", "Open chat"), Y.innerHTML = `<span class="ssk-open"
|
|
325
|
+
Y.className = "ssk-launcher", Y.setAttribute("aria-label", "Open chat"), Y.innerHTML = `<span class="ssk-open"><img src="${e}" alt="" /></span><span class="ssk-x" style="display:none">${a}</span><span class="ssk-pulse" aria-hidden="true"></span>`;
|
|
281
326
|
let X = document.createElement("div");
|
|
282
|
-
X.className = "ssk-greeting", X.textContent =
|
|
283
|
-
|
|
327
|
+
X.className = "ssk-greeting", X.textContent = f.welcomeMessage, p.append(J, X, Y), document.body.appendChild(p), Y.onclick = () => p.classList.toggle("open"), P.onclick = () => p.classList.remove("open"), w && setTimeout(() => {
|
|
328
|
+
p.classList.contains("open") || X.classList.add("shown"), setTimeout(() => X.classList.remove("shown"), 6e3);
|
|
284
329
|
}, 2500);
|
|
285
330
|
function Z(e) {
|
|
286
331
|
U.hidden = !e, e && (D.scrollTop = D.scrollHeight);
|
|
287
332
|
}
|
|
288
333
|
function Q() {
|
|
289
|
-
E.updatedAt = Date.now(), E.title =
|
|
290
|
-
let e =
|
|
291
|
-
e >= 0 &&
|
|
334
|
+
E.updatedAt = Date.now(), E.title = b(E.messages);
|
|
335
|
+
let e = S.findIndex((e) => e.id === E.id);
|
|
336
|
+
e >= 0 && S.splice(e, 1), S.unshift(E), g(r, S);
|
|
292
337
|
}
|
|
293
338
|
async function $() {
|
|
294
339
|
let e = W.value.trim();
|
|
@@ -300,18 +345,20 @@ async function C(t) {
|
|
|
300
345
|
};
|
|
301
346
|
E.messages.push(t), m(D, t), Q(), G.disabled = !0, Z(!0);
|
|
302
347
|
try {
|
|
303
|
-
let t = await (await fetch(`${
|
|
348
|
+
let t = await (await fetch(`${i}/answer`, {
|
|
304
349
|
method: "POST",
|
|
305
350
|
headers: { "Content-Type": "application/json" },
|
|
306
351
|
body: JSON.stringify({
|
|
307
|
-
embedToken:
|
|
352
|
+
embedToken: r,
|
|
308
353
|
query: e
|
|
309
354
|
})
|
|
310
|
-
})).json(),
|
|
355
|
+
})).json(), n = {
|
|
311
356
|
role: "bot",
|
|
312
|
-
text: t.ok ? t.reply : t.message || "Sorry, I couldn't process that right now."
|
|
357
|
+
text: t.ok ? t.reply : t.message || "Sorry, I couldn't process that right now.",
|
|
358
|
+
sources: Array.isArray(t.sources) && t.sources.length ? t.sources : void 0,
|
|
359
|
+
actions: Array.isArray(t.actions) && t.actions.length ? t.actions : void 0
|
|
313
360
|
};
|
|
314
|
-
E.messages.push(
|
|
361
|
+
E.messages.push(n), m(D, n);
|
|
315
362
|
} catch {
|
|
316
363
|
let e = {
|
|
317
364
|
role: "bot",
|
|
@@ -324,15 +371,15 @@ async function C(t) {
|
|
|
324
371
|
}
|
|
325
372
|
G.onclick = $, W.addEventListener("keydown", (e) => {
|
|
326
373
|
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), $());
|
|
327
|
-
}),
|
|
374
|
+
}), C(i, r), ee(i, r);
|
|
328
375
|
}
|
|
329
|
-
function
|
|
376
|
+
function T() {
|
|
330
377
|
let e = document.currentScript || Array.from(document.getElementsByTagName("script")).find((e) => /widget(\.global)?\.js/.test(e.src)), t = e?.dataset.token;
|
|
331
|
-
t &&
|
|
378
|
+
t && w({
|
|
332
379
|
token: t,
|
|
333
380
|
apiBase: e?.dataset.apiBase
|
|
334
381
|
});
|
|
335
382
|
}
|
|
336
|
-
typeof document < "u" &&
|
|
383
|
+
typeof document < "u" && T();
|
|
337
384
|
//#endregion
|
|
338
|
-
export {
|
|
385
|
+
export { w as init };
|
package/dist/widget.global.js
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=`https://us-central1-sendystack-fab32.cloudfunctions.net`,n=`sendystack-widget-root`,
|
|
2
|
-
#${
|
|
3
|
-
#${
|
|
4
|
-
.ssk-launcher{position:relative;width:60px;height:60px;border-radius:50%;border:none;cursor:pointer;color
|
|
5
|
-
background
|
|
1
|
+
var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=`https://us-central1-sendystack-fab32.cloudfunctions.net`,n=`https://app.sendystack.org/sendy_stack_favico.png`,r=`sendystack-widget-root`,i=40,a=e=>`sendystack_sessions_${e}`,o=e=>`sendystack_current_${e}`,s=e=>`sendystack_crawled_${e}`,c=`<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>`,l=`<svg viewBox="0 0 24 24" width="19" height="19" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l16-7-7 16-2-7-7-2z"/></svg>`,u=`<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3"/></svg>`,d=`<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>`,f=`<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>`;async function p(e,t){let n=await(await fetch(`${e}/embedConfig?embedToken=${encodeURIComponent(t)}`)).json();if(!n.ok)throw Error(n.error||`failed to load widget config`);return{...n.appearance,whiteLabel:!!n.whiteLabel}}function m(e){let t=e.position===`left`?`left`:`right`,n=document.createElement(`style`);n.textContent=`
|
|
2
|
+
#${r} *{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}
|
|
3
|
+
#${r}{position:fixed;${t}:20px;bottom:20px;z-index:2147483000;}
|
|
4
|
+
.ssk-launcher{position:relative;width:60px;height:60px;border-radius:50%;border:none;cursor:pointer;color:${e.accent};
|
|
5
|
+
background:#fff;box-shadow:0 16px 36px rgba(0,0,0,.22),0 0 0 1px rgba(27,39,51,.05);
|
|
6
6
|
display:flex;align-items:center;justify-content:center;transition:transform .25s cubic-bezier(.16,1,.3,1);margin-left:auto;}
|
|
7
7
|
.ssk-launcher:hover{transform:translateY(-3px) scale(1.04);}
|
|
8
8
|
.ssk-launcher:active{transform:scale(.96);}
|
|
9
9
|
.ssk-launcher .ssk-open{display:flex;} .ssk-launcher .ssk-x{display:none;}
|
|
10
|
-
|
|
10
|
+
.ssk-launcher .ssk-open img{width:32px;height:32px;object-fit:contain;}
|
|
11
|
+
#${r}.open .ssk-launcher .ssk-open{display:none;} #${r}.open .ssk-launcher .ssk-x{display:flex;}
|
|
11
12
|
.ssk-pulse{position:absolute;inset:0;border-radius:50%;background:${e.accent};opacity:.5;z-index:-1;animation:sskPulse 2.4s ease-out infinite;}
|
|
12
13
|
@keyframes sskPulse{0%{transform:scale(1);opacity:.5;}70%,100%{transform:scale(1.7);opacity:0;}}
|
|
13
14
|
@media(prefers-reduced-motion:reduce){.ssk-pulse{animation:none;}}
|
|
14
|
-
.ssk-greeting{position:absolute;bottom:72px;${t}:0;max-width:
|
|
15
|
+
.ssk-greeting{position:absolute;bottom:72px;${t}:0;width:max-content;max-width:min(300px,calc(100vw - 48px));padding:11px 16px;border-radius:14px;background:#fff;
|
|
15
16
|
color:#1b2733;font-size:13.5px;line-height:1.4;font-weight:600;box-shadow:0 16px 38px rgba(27,39,51,.18);
|
|
16
17
|
transform:translateY(8px);opacity:0;pointer-events:none;transition:opacity .3s,transform .3s;}
|
|
17
18
|
.ssk-greeting.shown{opacity:1;transform:translateY(0);}
|
|
18
|
-
#${
|
|
19
|
+
#${r}.open .ssk-greeting{display:none;}
|
|
19
20
|
.ssk-panel{position:absolute;bottom:74px;${t}:0;width:368px;max-width:calc(100vw - 32px);height:560px;
|
|
20
21
|
max-height:calc(100vh - 110px);background:#fff;border-radius:20px;overflow:hidden;display:flex;flex-direction:column;
|
|
21
22
|
box-shadow:0 36px 80px rgba(20,20,30,.3);border:1px solid rgba(27,39,51,.08);
|
|
22
23
|
transform:translateY(14px) scale(.96);opacity:0;pointer-events:none;transform-origin:bottom ${t};
|
|
23
24
|
transition:transform .25s cubic-bezier(.16,1,.3,1),opacity .2s;}
|
|
24
|
-
#${
|
|
25
|
+
#${r}.open .ssk-panel{transform:translateY(0) scale(1);opacity:1;pointer-events:auto;}
|
|
25
26
|
.ssk-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:13px 14px;flex-shrink:0;
|
|
26
27
|
background:linear-gradient(135deg,${e.accent2},${e.accent});color:#fff;}
|
|
27
28
|
.ssk-id{display:flex;align-items:center;gap:9px;min-width:0;}
|
|
28
29
|
.ssk-avatar{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;
|
|
29
|
-
background
|
|
30
|
+
background:#fff;flex:0 0 auto;}
|
|
31
|
+
.ssk-avatar img{width:22px;height:22px;object-fit:contain;}
|
|
30
32
|
.ssk-id-text{min-width:0;}
|
|
31
33
|
.ssk-id-text strong{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
32
34
|
.ssk-status{display:flex;align-items:center;gap:5px;font-size:11px;opacity:.9;}
|
|
@@ -53,8 +55,8 @@ var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`M
|
|
|
53
55
|
.ssk-history-item.active{background:rgba(226,112,15,.1);}
|
|
54
56
|
.ssk-history-title{display:block;font-size:13.5px;font-weight:600;color:#1b2733;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
55
57
|
.ssk-history-time{display:block;font-size:11px;color:#9aa3ad;margin-top:2px;}
|
|
56
|
-
.ssk-msg{display:flex;max-width:86%;}
|
|
57
|
-
.ssk-msg.bot{align-self:flex-start;} .ssk-msg.user{align-self:flex-end;}
|
|
58
|
+
.ssk-msg{display:flex;flex-direction:column;align-items:flex-start;max-width:86%;}
|
|
59
|
+
.ssk-msg.bot{align-self:flex-start;} .ssk-msg.user{align-self:flex-end;align-items:flex-end;}
|
|
58
60
|
.ssk-bubble-text{padding:10px 13px;border-radius:15px;font-size:14px;line-height:1.5;word-wrap:break-word;}
|
|
59
61
|
.ssk-msg.bot .ssk-bubble-text{background:#fff;border:1px solid rgba(27,39,51,.08);border-bottom-left-radius:5px;
|
|
60
62
|
box-shadow:0 5px 14px rgba(27,39,51,.05);color:#1b2733;}
|
|
@@ -62,6 +64,18 @@ var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`M
|
|
|
62
64
|
.ssk-bubble-text a{color:${e.accent};font-weight:700;text-decoration:underline;}
|
|
63
65
|
.ssk-msg.user .ssk-bubble-text a{color:#fff;}
|
|
64
66
|
.ssk-bubble-text p{margin:0 0 7px;} .ssk-bubble-text p:last-child{margin:0;}
|
|
67
|
+
.ssk-sources{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px;}
|
|
68
|
+
.ssk-source-pill{display:inline-flex;align-items:center;padding:5px 11px;border-radius:999px;
|
|
69
|
+
background:rgba(27,39,51,.05);color:${e.accent};font-size:12px;font-weight:600;
|
|
70
|
+
text-decoration:none;border:1px solid rgba(27,39,51,.08);}
|
|
71
|
+
.ssk-source-pill:hover{background:rgba(27,39,51,.08);}
|
|
72
|
+
.ssk-action-btn{margin-top:7px;border:none;border-radius:12px;padding:9px 15px;font-size:13px;font-weight:700;
|
|
73
|
+
cursor:pointer;color:#fff;background:linear-gradient(135deg,${e.accent2},${e.accent});
|
|
74
|
+
box-shadow:0 6px 16px rgba(0,0,0,.15);transition:transform .15s;}
|
|
75
|
+
.ssk-action-btn:hover{transform:translateY(-1px);}
|
|
76
|
+
.ssk-action-btn:disabled{cursor:default;transform:none;}
|
|
77
|
+
.ssk-action-btn.ssk-action-done{opacity:.75;}
|
|
78
|
+
.ssk-action-btn.ssk-action-missing{background:rgba(27,39,51,.08);color:#6b7280;box-shadow:none;}
|
|
65
79
|
.ssk-typing{padding:0 14px 10px;flex-shrink:0;}
|
|
66
80
|
.ssk-typing[hidden]{display:none;}
|
|
67
81
|
.ssk-dots{display:inline-flex;gap:5px;padding:10px 13px;background:#fff;border:1px solid rgba(27,39,51,.08);
|
|
@@ -81,4 +95,4 @@ var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`M
|
|
|
81
95
|
.ssk-sendbtn:disabled{opacity:.6;cursor:default;transform:none;}
|
|
82
96
|
.ssk-foot{text-align:center;font-size:10.5px;color:#9aa3ad;padding:0 8px 9px;background:#fff;flex-shrink:0;}
|
|
83
97
|
.ssk-foot a{color:inherit;text-decoration:underline;}
|
|
84
|
-
`,document.head.appendChild(
|
|
98
|
+
`,document.head.appendChild(n)}function h(e){return`<p>${e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g,`<a href="$2" target="_blank" rel="noopener">$1</a>`).replace(/\*\*([^*]+)\*\*/g,`<strong>$1</strong>`).replace(/\n{2,}/g,`</p><p>`).replace(/\n/g,`<br>`)}</p>`}function g(e){let t=document.createElement(`button`);t.type=`button`,t.className=`ssk-action-btn`,t.textContent=e.label;let n=!e.confirmRequired;return t.onclick=()=>{let r=e.selector?document.querySelector(e.selector):null;if(!r){if(e.fallbackUrl){location.href=e.fallbackUrl;return}t.textContent=`Couldn't find that on this page`,t.classList.add(`ssk-action-missing`),t.disabled=!0;return}if(!n){n=!0,t.textContent=`Click to confirm: ${e.label}`;return}r.click(),t.textContent=`Done ✓`,t.disabled=!0,t.classList.add(`ssk-action-done`)},t}function _(e,t){let n=document.createElement(`div`);n.className=`ssk-msg ${t.role}`;let r=document.createElement(`div`);if(r.className=`ssk-bubble-text`,r.innerHTML=h(t.text),n.appendChild(r),t.sources?.length){let e=document.createElement(`div`);e.className=`ssk-sources`;for(let n of t.sources){let t=document.createElement(`a`);t.className=`ssk-source-pill`,t.href=n.url,t.textContent=n.title||n.url,e.appendChild(t)}n.appendChild(e)}for(let e of t.actions||[])n.appendChild(g(e));e.appendChild(n),e.scrollTop=e.scrollHeight}function v(e){try{return JSON.parse(localStorage.getItem(a(e))||`[]`)}catch{return[]}}function y(e,t){try{localStorage.setItem(a(e),JSON.stringify(t.slice(0,i)))}catch{}}function b(e){try{return localStorage.getItem(o(e))}catch{return null}}function x(e,t){try{localStorage.setItem(o(e),t)}catch{}}function S(){return`s_${Date.now()}_${Math.random().toString(36).slice(2,8)}`}function ee(e){let t=e.find(e=>e.role===`user`);return t?t.text.slice(0,60):`New conversation`}function te(e){let t=new Date(e),n=new Date;return t.toDateString()===n.toDateString()?t.toLocaleTimeString(void 0,{hour:`numeric`,minute:`2-digit`}):t.toLocaleDateString(void 0,{month:`short`,day:`numeric`})}function C(){let e=document.body.cloneNode(!0);e.querySelectorAll(`script,style,nav,header,footer,svg,noscript,#${r}`).forEach(e=>e.remove());let t=(e.textContent||``).replace(/\s+/g,` `).trim();return{title:document.title,text:t}}async function w(e,t){let{title:n,text:r}=C();r.length<40||await fetch(`${e}/ingest`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({embedToken:t,items:[{url:location.href,title:n,text:r}]})}).catch(()=>{})}async function T(e,t){let n=!1;try{n=!!sessionStorage.getItem(s(t)),sessionStorage.setItem(s(t),`1`)}catch{}n||await fetch(`${e}/crawlSite`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({embedToken:t})}).catch(()=>{})}async function E(e){if(typeof document>`u`||document.getElementById(r))return;let i=(e.token||``).trim();if(!i){console.error(`[Sendystack] init() called without a token`);return}let a=e.apiBase||t,o;try{o=await p(a,i)}catch(e){console.error(`[Sendystack] failed to load widget config:`,e);return}m(o);let s=document.createElement(`div`);s.id=r;let h=v(i),g=h.length===0,C=b(i),E=h.find(e=>e.id===C);E||(E={id:S(),title:`New conversation`,messages:[],updatedAt:Date.now()},h.unshift(E),C=E.id,x(i,C),y(i,h));let D=document.createElement(`div`);D.className=`ssk-body`;function O(){D.innerHTML=``;let e=E.messages.length?E.messages:[{role:`bot`,text:o.welcomeMessage}];for(let t of e)_(D,t)}O();let k=document.createElement(`span`);k.className=`ssk-avatar`,k.innerHTML=`<img src="${n}" alt="" />`;let A=document.createElement(`div`);A.className=`ssk-id-text`,A.innerHTML=`<strong>${o.assistantName}</strong><span class="ssk-status"><span class="ssk-dot"></span>Online</span>`;let j=document.createElement(`div`);j.className=`ssk-id`,j.append(k,A);let M=document.createElement(`button`);M.className=`ssk-iconbtn`,M.innerHTML=u,M.setAttribute(`aria-label`,`Chat history`);let N=document.createElement(`button`);N.className=`ssk-iconbtn`,N.innerHTML=d,N.setAttribute(`aria-label`,`New chat`);let P=document.createElement(`button`);P.className=`ssk-closebtn`,P.innerHTML=c,P.setAttribute(`aria-label`,`Close chat`);let F=document.createElement(`div`);F.className=`ssk-headbtns`,F.append(M,N,P);let I=document.createElement(`div`);I.className=`ssk-head`,I.append(j,F);let L=document.createElement(`button`);L.className=`ssk-history-back`,L.innerHTML=f,L.setAttribute(`aria-label`,`Back to chat`);let R=document.createElement(`h4`);R.textContent=`Chat history`;let z=document.createElement(`div`);z.className=`ssk-history-head`,z.append(L,R);let B=document.createElement(`div`);B.className=`ssk-history-list`;let V=document.createElement(`div`);V.className=`ssk-history`,V.append(z,B);function H(){if(B.innerHTML=``,!h.length){let e=document.createElement(`div`);e.className=`ssk-history-empty`,e.textContent=`No past conversations yet.`,B.appendChild(e);return}for(let e of h){let t=document.createElement(`button`);t.className=`ssk-history-item${e.id===C?` active`:``}`,t.innerHTML=`<span class="ssk-history-title">${e.title}</span><span class="ssk-history-time">${te(e.updatedAt)}</span>`,t.onclick=()=>{E=e,C=e.id,x(i,C),O(),H(),V.classList.remove(`shown`)},B.appendChild(t)}}M.onclick=()=>{H(),V.classList.add(`shown`)},L.onclick=()=>V.classList.remove(`shown`),N.onclick=()=>{E.messages.length&&(E={id:S(),title:`New conversation`,messages:[],updatedAt:Date.now()},h.unshift(E),C=E.id,x(i,C),y(i,h),O(),V.classList.remove(`shown`))};let U=document.createElement(`div`);U.className=`ssk-typing`,U.hidden=!0,U.innerHTML=`<span class="ssk-dots"><i></i><i></i><i></i></span>`;let W=document.createElement(`textarea`);W.rows=1,W.maxLength=4e3,W.placeholder=`Ask me anything…`;let G=document.createElement(`button`);G.className=`ssk-sendbtn`,G.innerHTML=l,G.setAttribute(`aria-label`,`Send`);let K=document.createElement(`div`);K.className=`ssk-inputrow`,K.append(W,G);let q=document.createElement(`div`);q.className=`ssk-foot`,q.textContent=o.whiteLabel?`AI can make mistakes — confirm important details.`:`AI can make mistakes — confirm important details. · Powered by Sendystack`;let J=document.createElement(`div`);J.className=`ssk-panel`,J.append(I,D,U,K,q,V);let Y=document.createElement(`button`);Y.className=`ssk-launcher`,Y.setAttribute(`aria-label`,`Open chat`),Y.innerHTML=`<span class="ssk-open"><img src="${n}" alt="" /></span><span class="ssk-x" style="display:none">${c}</span><span class="ssk-pulse" aria-hidden="true"></span>`;let X=document.createElement(`div`);X.className=`ssk-greeting`,X.textContent=o.welcomeMessage,s.append(J,X,Y),document.body.appendChild(s),Y.onclick=()=>s.classList.toggle(`open`),P.onclick=()=>s.classList.remove(`open`),g&&setTimeout(()=>{s.classList.contains(`open`)||X.classList.add(`shown`),setTimeout(()=>X.classList.remove(`shown`),6e3)},2500);function Z(e){U.hidden=!e,e&&(D.scrollTop=D.scrollHeight)}function Q(){E.updatedAt=Date.now(),E.title=ee(E.messages);let e=h.findIndex(e=>e.id===E.id);e>=0&&h.splice(e,1),h.unshift(E),y(i,h)}async function $(){let e=W.value.trim();if(!e)return;W.value=``;let t={role:`user`,text:e};E.messages.push(t),_(D,t),Q(),G.disabled=!0,Z(!0);try{let t=await(await fetch(`${a}/answer`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({embedToken:i,query:e})})).json(),n={role:`bot`,text:t.ok?t.reply:t.message||`Sorry, I couldn't process that right now.`,sources:Array.isArray(t.sources)&&t.sources.length?t.sources:void 0,actions:Array.isArray(t.actions)&&t.actions.length?t.actions:void 0};E.messages.push(n),_(D,n)}catch{let e={role:`bot`,text:`I couldn't reach the server. Please try again.`};E.messages.push(e),_(D,e)}finally{Z(!1),G.disabled=!1,Q()}}G.onclick=$,W.addEventListener(`keydown`,e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),$())}),w(a,i),T(a,i)}function D(){let e=document.currentScript||Array.from(document.getElementsByTagName(`script`)).find(e=>/widget(\.global)?\.js/.test(e.src)),t=e?.dataset.token;t&&E({token:t,apiBase:e?.dataset.apiBase})}return typeof document<`u`&&D(),e.init=E,e})({});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendystack/widget",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Universal AI chat widget for any website -- auto-injects the chatbot, crawls your site into the knowledge base, and feeds Claude/ChatGPT/Gemini via MCP. Appearance is managed at app.sendystack.org.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|