@sendystack/widget 0.1.3 → 0.1.5
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 +97 -50
- package/dist/widget.global.js +15 -3
- package/package.json +1 -1
package/dist/index.es.js
CHANGED
|
@@ -8,7 +8,7 @@ async function u(e, t) {
|
|
|
8
8
|
whiteLabel: !!n.whiteLabel
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function d(e) {
|
|
12
12
|
let n = e.position === "left" ? "left" : "right", r = document.createElement("style");
|
|
13
13
|
r.textContent = `
|
|
14
14
|
#${t} *{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}
|
|
@@ -67,8 +67,8 @@ function ee(e) {
|
|
|
67
67
|
.ssk-history-item.active{background:rgba(226,112,15,.1);}
|
|
68
68
|
.ssk-history-title{display:block;font-size:13.5px;font-weight:600;color:#1b2733;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
69
69
|
.ssk-history-time{display:block;font-size:11px;color:#9aa3ad;margin-top:2px;}
|
|
70
|
-
.ssk-msg{display:flex;max-width:86%;}
|
|
71
|
-
.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;}
|
|
72
72
|
.ssk-bubble-text{padding:10px 13px;border-radius:15px;font-size:14px;line-height:1.5;word-wrap:break-word;}
|
|
73
73
|
.ssk-msg.bot .ssk-bubble-text{background:#fff;border:1px solid rgba(27,39,51,.08);border-bottom-left-radius:5px;
|
|
74
74
|
box-shadow:0 5px 14px rgba(27,39,51,.05);color:#1b2733;}
|
|
@@ -76,6 +76,18 @@ function ee(e) {
|
|
|
76
76
|
.ssk-bubble-text a{color:${e.accent};font-weight:700;text-decoration:underline;}
|
|
77
77
|
.ssk-msg.user .ssk-bubble-text a{color:#fff;}
|
|
78
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;}
|
|
79
91
|
.ssk-typing{padding:0 14px 10px;flex-shrink:0;}
|
|
80
92
|
.ssk-typing[hidden]{display:none;}
|
|
81
93
|
.ssk-dots{display:inline-flex;gap:5px;padding:10px 13px;background:#fff;border:1px solid rgba(27,39,51,.08);
|
|
@@ -97,47 +109,78 @@ function ee(e) {
|
|
|
97
109
|
.ssk-foot a{color:inherit;text-decoration:underline;}
|
|
98
110
|
`, document.head.appendChild(r);
|
|
99
111
|
}
|
|
100
|
-
function
|
|
112
|
+
function f(e) {
|
|
101
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>`;
|
|
102
114
|
}
|
|
103
|
-
function
|
|
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
|
+
}
|
|
136
|
+
function m(e, t) {
|
|
104
137
|
let n = document.createElement("div");
|
|
105
138
|
n.className = `ssk-msg ${t.role}`;
|
|
106
139
|
let r = document.createElement("div");
|
|
107
|
-
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;
|
|
108
151
|
}
|
|
109
|
-
function
|
|
152
|
+
function h(e) {
|
|
110
153
|
try {
|
|
111
154
|
return JSON.parse(localStorage.getItem(n(e)) || "[]");
|
|
112
155
|
} catch {
|
|
113
156
|
return [];
|
|
114
157
|
}
|
|
115
158
|
}
|
|
116
|
-
function
|
|
159
|
+
function g(e, t) {
|
|
117
160
|
try {
|
|
118
161
|
localStorage.setItem(n(e), JSON.stringify(t.slice(0, 40)));
|
|
119
162
|
} catch {}
|
|
120
163
|
}
|
|
121
|
-
function
|
|
164
|
+
function _(e) {
|
|
122
165
|
try {
|
|
123
166
|
return localStorage.getItem(r(e));
|
|
124
167
|
} catch {
|
|
125
168
|
return null;
|
|
126
169
|
}
|
|
127
170
|
}
|
|
128
|
-
function
|
|
171
|
+
function v(e, t) {
|
|
129
172
|
try {
|
|
130
173
|
localStorage.setItem(r(e), t);
|
|
131
174
|
} catch {}
|
|
132
175
|
}
|
|
133
|
-
function
|
|
176
|
+
function y() {
|
|
134
177
|
return `s_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
135
178
|
}
|
|
136
|
-
function
|
|
179
|
+
function b(e) {
|
|
137
180
|
let t = e.find((e) => e.role === "user");
|
|
138
181
|
return t ? t.text.slice(0, 60) : "New conversation";
|
|
139
182
|
}
|
|
140
|
-
function
|
|
183
|
+
function x(e) {
|
|
141
184
|
let t = new Date(e), n = /* @__PURE__ */ new Date();
|
|
142
185
|
return t.toDateString() === n.toDateString() ? t.toLocaleTimeString(void 0, {
|
|
143
186
|
hour: "numeric",
|
|
@@ -147,7 +190,7 @@ function y(e) {
|
|
|
147
190
|
day: "numeric"
|
|
148
191
|
});
|
|
149
192
|
}
|
|
150
|
-
function
|
|
193
|
+
function S() {
|
|
151
194
|
let e = document.body.cloneNode(!0);
|
|
152
195
|
e.querySelectorAll(`script,style,nav,header,footer,svg,noscript,#${t}`).forEach((e) => e.remove());
|
|
153
196
|
let n = (e.textContent || "").replace(/\s+/g, " ").trim();
|
|
@@ -156,8 +199,8 @@ function b() {
|
|
|
156
199
|
text: n
|
|
157
200
|
};
|
|
158
201
|
}
|
|
159
|
-
async function
|
|
160
|
-
let { title: n, text: r } =
|
|
202
|
+
async function C(e, t) {
|
|
203
|
+
let { title: n, text: r } = S();
|
|
161
204
|
r.length < 40 || await fetch(`${e}/ingest`, {
|
|
162
205
|
method: "POST",
|
|
163
206
|
headers: { "Content-Type": "application/json" },
|
|
@@ -171,7 +214,7 @@ async function x(e, t) {
|
|
|
171
214
|
})
|
|
172
215
|
}).catch(() => {});
|
|
173
216
|
}
|
|
174
|
-
async function
|
|
217
|
+
async function ee(e, t) {
|
|
175
218
|
let n = !1;
|
|
176
219
|
try {
|
|
177
220
|
n = !!sessionStorage.getItem(i(t)), sessionStorage.setItem(i(t), "1");
|
|
@@ -182,45 +225,45 @@ async function S(e, t) {
|
|
|
182
225
|
body: JSON.stringify({ embedToken: t })
|
|
183
226
|
}).catch(() => {});
|
|
184
227
|
}
|
|
185
|
-
async function
|
|
228
|
+
async function w(n) {
|
|
186
229
|
if (typeof document > "u" || document.getElementById(t)) return;
|
|
187
230
|
let r = (n.token || "").trim();
|
|
188
231
|
if (!r) {
|
|
189
232
|
console.error("[Sendystack] init() called without a token");
|
|
190
233
|
return;
|
|
191
234
|
}
|
|
192
|
-
let i = n.apiBase || "https://us-central1-sendystack-fab32.cloudfunctions.net",
|
|
235
|
+
let i = n.apiBase || "https://us-central1-sendystack-fab32.cloudfunctions.net", f;
|
|
193
236
|
try {
|
|
194
|
-
|
|
237
|
+
f = await u(i, r);
|
|
195
238
|
} catch (e) {
|
|
196
239
|
console.error("[Sendystack] failed to load widget config:", e);
|
|
197
240
|
return;
|
|
198
241
|
}
|
|
199
|
-
|
|
200
|
-
let
|
|
201
|
-
|
|
202
|
-
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);
|
|
203
246
|
E || (E = {
|
|
204
|
-
id:
|
|
247
|
+
id: y(),
|
|
205
248
|
title: "New conversation",
|
|
206
249
|
messages: [],
|
|
207
250
|
updatedAt: Date.now()
|
|
208
|
-
},
|
|
251
|
+
}, S.unshift(E), T = E.id, v(r, T), g(r, S));
|
|
209
252
|
let D = document.createElement("div");
|
|
210
253
|
D.className = "ssk-body";
|
|
211
254
|
function O() {
|
|
212
255
|
D.innerHTML = "";
|
|
213
256
|
let e = E.messages.length ? E.messages : [{
|
|
214
257
|
role: "bot",
|
|
215
|
-
text:
|
|
258
|
+
text: f.welcomeMessage
|
|
216
259
|
}];
|
|
217
|
-
for (let t of e)
|
|
260
|
+
for (let t of e) m(D, t);
|
|
218
261
|
}
|
|
219
262
|
O();
|
|
220
263
|
let k = document.createElement("span");
|
|
221
264
|
k.className = "ssk-avatar", k.innerHTML = `<img src="${e}" alt="" />`;
|
|
222
265
|
let A = document.createElement("div");
|
|
223
|
-
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>`;
|
|
224
267
|
let j = document.createElement("div");
|
|
225
268
|
j.className = "ssk-id", j.append(k, A);
|
|
226
269
|
let M = document.createElement("button");
|
|
@@ -244,15 +287,15 @@ async function C(n) {
|
|
|
244
287
|
let V = document.createElement("div");
|
|
245
288
|
V.className = "ssk-history", V.append(z, B);
|
|
246
289
|
function H() {
|
|
247
|
-
if (B.innerHTML = "", !
|
|
290
|
+
if (B.innerHTML = "", !S.length) {
|
|
248
291
|
let e = document.createElement("div");
|
|
249
292
|
e.className = "ssk-history-empty", e.textContent = "No past conversations yet.", B.appendChild(e);
|
|
250
293
|
return;
|
|
251
294
|
}
|
|
252
|
-
for (let e of
|
|
295
|
+
for (let e of S) {
|
|
253
296
|
let t = document.createElement("button");
|
|
254
|
-
t.className = `ssk-history-item${e.id === T ? " active" : ""}`, t.innerHTML = `<span class="ssk-history-title">${e.title}</span><span class="ssk-history-time">${
|
|
255
|
-
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");
|
|
256
299
|
}, B.appendChild(t);
|
|
257
300
|
}
|
|
258
301
|
}
|
|
@@ -260,11 +303,11 @@ async function C(n) {
|
|
|
260
303
|
H(), V.classList.add("shown");
|
|
261
304
|
}, L.onclick = () => V.classList.remove("shown"), N.onclick = () => {
|
|
262
305
|
E.messages.length && (E = {
|
|
263
|
-
id:
|
|
306
|
+
id: y(),
|
|
264
307
|
title: "New conversation",
|
|
265
308
|
messages: [],
|
|
266
309
|
updatedAt: Date.now()
|
|
267
|
-
},
|
|
310
|
+
}, S.unshift(E), T = E.id, v(r, T), g(r, S), O(), V.classList.remove("shown"));
|
|
268
311
|
};
|
|
269
312
|
let U = document.createElement("div");
|
|
270
313
|
U.className = "ssk-typing", U.hidden = !0, U.innerHTML = "<span class=\"ssk-dots\"><i></i><i></i><i></i></span>";
|
|
@@ -275,22 +318,22 @@ async function C(n) {
|
|
|
275
318
|
let K = document.createElement("div");
|
|
276
319
|
K.className = "ssk-inputrow", K.append(W, G);
|
|
277
320
|
let q = document.createElement("div");
|
|
278
|
-
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";
|
|
279
322
|
let J = document.createElement("div");
|
|
280
323
|
J.className = "ssk-panel", J.append(I, D, U, K, q, V);
|
|
281
324
|
let Y = document.createElement("button");
|
|
282
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>`;
|
|
283
326
|
let X = document.createElement("div");
|
|
284
|
-
X.className = "ssk-greeting", X.textContent =
|
|
285
|
-
|
|
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);
|
|
286
329
|
}, 2500);
|
|
287
330
|
function Z(e) {
|
|
288
331
|
U.hidden = !e, e && (D.scrollTop = D.scrollHeight);
|
|
289
332
|
}
|
|
290
333
|
function Q() {
|
|
291
|
-
E.updatedAt = Date.now(), E.title =
|
|
292
|
-
let e =
|
|
293
|
-
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);
|
|
294
337
|
}
|
|
295
338
|
async function $() {
|
|
296
339
|
let e = W.value.trim();
|
|
@@ -300,7 +343,7 @@ async function C(n) {
|
|
|
300
343
|
role: "user",
|
|
301
344
|
text: e
|
|
302
345
|
};
|
|
303
|
-
E.messages.push(t),
|
|
346
|
+
E.messages.push(t), m(D, t), Q(), G.disabled = !0, Z(!0);
|
|
304
347
|
try {
|
|
305
348
|
let t = await (await fetch(`${i}/answer`, {
|
|
306
349
|
method: "POST",
|
|
@@ -311,30 +354,34 @@ async function C(n) {
|
|
|
311
354
|
})
|
|
312
355
|
})).json(), n = {
|
|
313
356
|
role: "bot",
|
|
314
|
-
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
|
|
315
360
|
};
|
|
316
|
-
E.messages.push(n),
|
|
361
|
+
E.messages.push(n), m(D, n), t.navigate?.url && setTimeout(() => {
|
|
362
|
+
location.href = t.navigate.url;
|
|
363
|
+
}, 700);
|
|
317
364
|
} catch {
|
|
318
365
|
let e = {
|
|
319
366
|
role: "bot",
|
|
320
367
|
text: "I couldn't reach the server. Please try again."
|
|
321
368
|
};
|
|
322
|
-
E.messages.push(e),
|
|
369
|
+
E.messages.push(e), m(D, e);
|
|
323
370
|
} finally {
|
|
324
371
|
Z(!1), G.disabled = !1, Q();
|
|
325
372
|
}
|
|
326
373
|
}
|
|
327
374
|
G.onclick = $, W.addEventListener("keydown", (e) => {
|
|
328
375
|
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), $());
|
|
329
|
-
}),
|
|
376
|
+
}), C(i, r), ee(i, r);
|
|
330
377
|
}
|
|
331
|
-
function
|
|
378
|
+
function T() {
|
|
332
379
|
let e = document.currentScript || Array.from(document.getElementsByTagName("script")).find((e) => /widget(\.global)?\.js/.test(e.src)), t = e?.dataset.token;
|
|
333
|
-
t &&
|
|
380
|
+
t && w({
|
|
334
381
|
token: t,
|
|
335
382
|
apiBase: e?.dataset.apiBase
|
|
336
383
|
});
|
|
337
384
|
}
|
|
338
|
-
typeof document < "u" &&
|
|
385
|
+
typeof document < "u" && T();
|
|
339
386
|
//#endregion
|
|
340
|
-
export {
|
|
387
|
+
export { w as init };
|
package/dist/widget.global.js
CHANGED
|
@@ -55,8 +55,8 @@ var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`M
|
|
|
55
55
|
.ssk-history-item.active{background:rgba(226,112,15,.1);}
|
|
56
56
|
.ssk-history-title{display:block;font-size:13.5px;font-weight:600;color:#1b2733;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
57
57
|
.ssk-history-time{display:block;font-size:11px;color:#9aa3ad;margin-top:2px;}
|
|
58
|
-
.ssk-msg{display:flex;max-width:86%;}
|
|
59
|
-
.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;}
|
|
60
60
|
.ssk-bubble-text{padding:10px 13px;border-radius:15px;font-size:14px;line-height:1.5;word-wrap:break-word;}
|
|
61
61
|
.ssk-msg.bot .ssk-bubble-text{background:#fff;border:1px solid rgba(27,39,51,.08);border-bottom-left-radius:5px;
|
|
62
62
|
box-shadow:0 5px 14px rgba(27,39,51,.05);color:#1b2733;}
|
|
@@ -64,6 +64,18 @@ var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`M
|
|
|
64
64
|
.ssk-bubble-text a{color:${e.accent};font-weight:700;text-decoration:underline;}
|
|
65
65
|
.ssk-msg.user .ssk-bubble-text a{color:#fff;}
|
|
66
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;}
|
|
67
79
|
.ssk-typing{padding:0 14px 10px;flex-shrink:0;}
|
|
68
80
|
.ssk-typing[hidden]{display:none;}
|
|
69
81
|
.ssk-dots{display:inline-flex;gap:5px;padding:10px 13px;background:#fff;border:1px solid rgba(27,39,51,.08);
|
|
@@ -83,4 +95,4 @@ var Sendystack=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`M
|
|
|
83
95
|
.ssk-sendbtn:disabled{opacity:.6;cursor:default;transform:none;}
|
|
84
96
|
.ssk-foot{text-align:center;font-size:10.5px;color:#9aa3ad;padding:0 8px 9px;background:#fff;flex-shrink:0;}
|
|
85
97
|
.ssk-foot a{color:inherit;text-decoration:underline;}
|
|
86
|
-
`,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,t){let n=document.createElement(`div`);n.className=`ssk-msg ${t.role}`;let r=document.createElement(`div`);r.className=`ssk-bubble-text`,r.innerHTML=h(t.text),n.appendChild(r),e.appendChild(n),e.scrollTop=e.scrollHeight}function
|
|
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),t.navigate?.url&&setTimeout(()=>{location.href=t.navigate.url},700)}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.5",
|
|
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",
|