rowsky-chatbot-widget 1.0.5 → 1.0.6
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/chatbot.mjs +158 -78
- package/dist/chatbot.umd.js +1 -1
- package/package.json +1 -1
package/dist/chatbot.mjs
CHANGED
|
@@ -37,69 +37,190 @@ const createWidgetAPI = (baseUrl) => {
|
|
|
37
37
|
captureLead: (token, leadData) => request("POST", "/widget/lead", leadData, token)
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
|
-
const
|
|
40
|
+
const STYLE_ID = "fluxia-widget-styles";
|
|
41
|
+
const CRITICAL_CSS = `
|
|
42
|
+
#fluxia-widget-root{all:initial;font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;line-height:1.5;color:#1f2937;--fw-header:#0f172a;--fw-white:#fff;--fw-green:#22c55e;--fw-red:#ef4444;--fw-red-dark:#dc2626;--fw-text:#1f2937;--fw-gray-100:#f3f4f6;--fw-gray-200:#e5e7eb;--fw-gray-300:#d1d5db;--fw-gray-bg:#fafbfc;--fw-radius:20px;--fw-shadow:0 20px 60px rgba(0,0,0,.25)}
|
|
43
|
+
#fluxia-widget-root *,#fluxia-widget-root *::before,#fluxia-widget-root *::after{box-sizing:border-box;margin:0;padding:0}
|
|
44
|
+
#fluxia-widget-root .fluxia-bubble{position:fixed;bottom:24px;right:24px;z-index:2147483646;width:60px;height:60px;border-radius:50%;border:none;background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 24px rgba(239,68,68,.5),0 0 0 4px rgba(255,255,255,.25);transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .3s,opacity .25s;opacity:1}
|
|
45
|
+
#fluxia-widget-root .fluxia-bubble.fw-hidden{transform:scale(0);opacity:0;pointer-events:none}
|
|
46
|
+
#fluxia-widget-root .fluxia-bubble svg{width:28px;height:28px;fill:#fff;stroke:none}
|
|
47
|
+
#fluxia-widget-root .fluxia-chatbox{position:fixed;bottom:10px;right:10px;z-index:2147483647;width:400px;height:600px;max-height:calc(100vh - 120px);border-radius:var(--fw-radius);background:var(--fw-white);box-shadow:var(--fw-shadow);display:flex;flex-direction:column;overflow:hidden;transform-origin:bottom right;transform:scale(0) translateY(20px);opacity:0;pointer-events:none;transition:transform .35s cubic-bezier(.34,1.56,.64,1),opacity .25s}
|
|
48
|
+
#fluxia-widget-root .fluxia-chatbox.fw-open{transform:scale(1) translateY(0);opacity:1;pointer-events:auto}
|
|
49
|
+
#fluxia-widget-root .fluxia-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;background:var(--fw-header);color:var(--fw-white);flex-shrink:0;border-radius:var(--fw-radius) var(--fw-radius) 0 0}
|
|
50
|
+
#fluxia-widget-root .fluxia-header-info{display:flex;align-items:center;gap:12px;flex:1;min-width:0}
|
|
51
|
+
#fluxia-widget-root .fluxia-avatar{width:42px;height:42px;min-width:42px;border-radius:50%;background:rgba(255,255,255,.12);border:2px solid rgba(34,197,94,.5);display:flex;align-items:center;justify-content:center;font-size:20px;overflow:hidden;color:#fff}
|
|
52
|
+
#fluxia-widget-root .fluxia-avatar img{width:100%;height:100%;object-fit:cover;border-radius:50%}
|
|
53
|
+
#fluxia-widget-root .fluxia-header-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}
|
|
54
|
+
#fluxia-widget-root .fluxia-title{font-weight:700;font-size:15px;color:var(--fw-white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
55
|
+
#fluxia-widget-root .fluxia-status{font-size:12px;color:var(--fw-green);display:flex;align-items:center;gap:6px;font-weight:600}
|
|
56
|
+
#fluxia-widget-root .fluxia-status-dot{width:7px;height:7px;border-radius:50%;background:var(--fw-green);display:inline-block;animation:fw-pulse 2s ease-in-out infinite}
|
|
57
|
+
@keyframes fw-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.3)}}
|
|
58
|
+
#fluxia-widget-root .fluxia-close{width:34px;height:34px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.08);border:none;color:var(--fw-white);cursor:pointer;border-radius:8px;transition:background .2s}
|
|
59
|
+
#fluxia-widget-root .fluxia-close:hover{background:rgba(255,255,255,.18)}
|
|
60
|
+
#fluxia-widget-root .fluxia-close svg{width:16px;height:16px}
|
|
61
|
+
#fluxia-widget-root .fluxia-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;background:var(--fw-white)}
|
|
62
|
+
#fluxia-widget-root .fluxia-msg{max-width:82%;padding:10px 14px;font-size:13.5px;line-height:1.55;word-wrap:break-word;overflow-wrap:break-word;animation:fw-msgIn .3s ease-out}
|
|
63
|
+
@keyframes fw-msgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
|
64
|
+
#fluxia-widget-root .fluxia-msg-assistant{align-self:flex-start;background:var(--fw-gray-100);color:var(--fw-text);border-radius:16px 16px 16px 4px}
|
|
65
|
+
#fluxia-widget-root .fluxia-msg-user{align-self:flex-end;background:var(--fw-header);color:var(--fw-white);border-radius:16px 16px 4px 16px}
|
|
66
|
+
#fluxia-widget-root .fluxia-msg-system{align-self:center;background:#fef3c7;color:#92400e;font-size:12px;padding:8px 14px;border-radius:8px;text-align:center;max-width:90%;border:1px solid #fde68a}
|
|
67
|
+
#fluxia-widget-root .fluxia-typing{display:flex;gap:5px;align-items:center;padding:4px 0}
|
|
68
|
+
#fluxia-widget-root .fluxia-typing-dot{width:7px;height:7px;border-radius:50%;background:#94a3b8;animation:fw-bounce 1.4s infinite ease-in-out}
|
|
69
|
+
#fluxia-widget-root .fluxia-typing-dot:nth-child(2){animation-delay:.16s}
|
|
70
|
+
#fluxia-widget-root .fluxia-typing-dot:nth-child(3){animation-delay:.32s}
|
|
71
|
+
@keyframes fw-bounce{0%,80%,100%{transform:scale(.7);opacity:.4}40%{transform:scale(1.1);opacity:1}}
|
|
72
|
+
#fluxia-widget-root .fluxia-input-area{padding:12px 14px;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);display:flex;align-items:center;gap:10px;flex-shrink:0}
|
|
73
|
+
#fluxia-widget-root .fluxia-input{flex:1;border:1.5px solid var(--fw-gray-300);border-radius:24px;padding:10px 16px;font-size:13px;font-family:inherit;outline:none;color:var(--fw-text);background:var(--fw-gray-bg);transition:border-color .2s,box-shadow .2s}
|
|
74
|
+
#fluxia-widget-root .fluxia-input::placeholder{color:#9ca3af}
|
|
75
|
+
#fluxia-widget-root .fluxia-input:focus{border-color:var(--fw-header);background:var(--fw-white);box-shadow:0 0 0 3px rgba(15,23,42,.06)}
|
|
76
|
+
#fluxia-widget-root .fluxia-input:disabled{opacity:.5;cursor:not-allowed}
|
|
77
|
+
#fluxia-widget-root .fluxia-send{width:40px;height:40px;min-width:40px;border-radius:50%;background:var(--fw-red);color:var(--fw-white);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s,transform .2s;flex-shrink:0}
|
|
78
|
+
#fluxia-widget-root .fluxia-send:hover{background:var(--fw-red-dark);transform:scale(1.08)}
|
|
79
|
+
#fluxia-widget-root .fluxia-send:active{transform:scale(.92)}
|
|
80
|
+
#fluxia-widget-root .fluxia-send:disabled{opacity:.4;cursor:not-allowed;transform:none}
|
|
81
|
+
#fluxia-widget-root .fluxia-send svg{width:18px;height:18px}
|
|
82
|
+
#fluxia-widget-root .fluxia-powered{text-align:center;padding:8px 0;font-size:11px;color:#9ca3af;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);flex-shrink:0}
|
|
83
|
+
#fluxia-widget-root .fluxia-powered a{color:#6b7280;text-decoration:none;font-weight:600}
|
|
84
|
+
#fluxia-widget-root[data-position="left"] .fluxia-bubble{left:24px;right:auto}
|
|
85
|
+
#fluxia-widget-root[data-position="left"] .fluxia-chatbox{left:24px;right:auto;transform-origin:bottom left}
|
|
86
|
+
@media(max-width:768px){#fluxia-widget-root .fluxia-chatbox{width:calc(100vw - 32px);max-width:400px;height:calc(100vh - 140px);max-height:600px;bottom:10px;right:10px}#fluxia-widget-root .fluxia-bubble{bottom:20px;right:16px;width:56px;height:56px}}
|
|
87
|
+
@media(max-width:480px){#fluxia-widget-root .fluxia-chatbox{position:fixed;top:0;left:0;right:0;bottom:0;width:100%;height:100%;max-width:none;max-height:none;border-radius:0;transform-origin:bottom center}#fluxia-widget-root .fluxia-chatbox.fw-open{border-radius:0}#fluxia-widget-root .fluxia-header{border-radius:0}#fluxia-widget-root .fluxia-bubble{bottom:16px;right:16px;width:52px;height:52px}#fluxia-widget-root .fluxia-bubble svg{width:24px;height:24px}#fluxia-widget-root .fluxia-avatar{width:38px;height:38px;min-width:38px}#fluxia-widget-root .fluxia-title{font-size:14px}#fluxia-widget-root .fluxia-msg{max-width:88%;font-size:13px}#fluxia-widget-root .fluxia-input{font-size:14px}#fluxia-widget-root .fluxia-send{width:38px;height:38px;min-width:38px}}
|
|
88
|
+
`;
|
|
89
|
+
const injectStyles = () => {
|
|
90
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
91
|
+
const el = document.createElement("style");
|
|
92
|
+
el.id = STYLE_ID;
|
|
93
|
+
el.textContent = CRITICAL_CSS;
|
|
94
|
+
document.head.appendChild(el);
|
|
95
|
+
};
|
|
96
|
+
const esc = (str) => {
|
|
97
|
+
const d = document.createElement("div");
|
|
98
|
+
d.textContent = str;
|
|
99
|
+
return d.innerHTML;
|
|
100
|
+
};
|
|
101
|
+
function widgetHTML({ botName, botAvatar }) {
|
|
102
|
+
const avatar = botAvatar ? `<img src="${esc(botAvatar)}" alt="Avatar" />` : "🤖";
|
|
103
|
+
return `
|
|
104
|
+
<button class="fluxia-bubble" aria-label="Abrir chat" title="Abrir chat">
|
|
105
|
+
<svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
106
|
+
</button>
|
|
107
|
+
|
|
108
|
+
<div class="fluxia-chatbox" role="dialog" aria-label="Chat">
|
|
109
|
+
<div class="fluxia-header">
|
|
110
|
+
<div class="fluxia-header-info">
|
|
111
|
+
<div class="fluxia-avatar">${avatar}</div>
|
|
112
|
+
<div class="fluxia-header-text">
|
|
113
|
+
<div class="fluxia-title">${botName}</div>
|
|
114
|
+
<div class="fluxia-status">
|
|
115
|
+
<span class="fluxia-status-dot"></span>
|
|
116
|
+
Online agora
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<button class="fluxia-close" aria-label="Fechar chat" title="Fechar">
|
|
121
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
|
|
122
|
+
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
|
123
|
+
</svg>
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div class="fluxia-messages"></div>
|
|
128
|
+
|
|
129
|
+
<div class="fluxia-input-area">
|
|
130
|
+
<input class="fluxia-input" type="text"
|
|
131
|
+
placeholder="Pergunte sobre leads, métricas ou integrações"
|
|
132
|
+
autocomplete="off" />
|
|
133
|
+
<button class="fluxia-send" title="Enviar">
|
|
134
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
|
|
135
|
+
stroke-linecap="round" stroke-linejoin="round">
|
|
136
|
+
<line x1="22" y1="2" x2="11" y2="13"/>
|
|
137
|
+
<polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
|
138
|
+
</svg>
|
|
139
|
+
</button>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div class="fluxia-powered">
|
|
143
|
+
Powered by <a href="https://rowsky.com.br/" target="_blank" rel="noopener">Rowsky</a>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
`;
|
|
147
|
+
}
|
|
148
|
+
const renderWidget = async ({ config, token, api, visitorId, botId }) => {
|
|
149
|
+
injectStyles();
|
|
41
150
|
const theme = config.theme || {};
|
|
42
|
-
const primaryColor = theme.primaryColor || "#dc2626";
|
|
43
151
|
const position = theme.position || "right";
|
|
44
152
|
const botName = config.botName || config.name || "Assistente";
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
153
|
+
const botAvatar = config.botAvatar || "";
|
|
154
|
+
const customCss = config.customCss || "";
|
|
155
|
+
const root = document.createElement("div");
|
|
156
|
+
root.id = "fluxia-widget-root";
|
|
157
|
+
root.dataset.position = position;
|
|
158
|
+
root.innerHTML = widgetHTML({ botName: esc(botName), botAvatar });
|
|
159
|
+
document.body.appendChild(root);
|
|
160
|
+
if (customCss && customCss.trim()) {
|
|
161
|
+
const s = document.createElement("style");
|
|
162
|
+
s.id = "fluxia-widget-custom";
|
|
163
|
+
s.textContent = customCss;
|
|
164
|
+
document.head.appendChild(s);
|
|
165
|
+
}
|
|
166
|
+
const bubble = root.querySelector(".fluxia-bubble");
|
|
167
|
+
const chatbox = root.querySelector(".fluxia-chatbox");
|
|
168
|
+
const closeBtn = root.querySelector(".fluxia-close");
|
|
169
|
+
const input = root.querySelector(".fluxia-input");
|
|
170
|
+
const sendBtn = root.querySelector(".fluxia-send");
|
|
171
|
+
const messages = root.querySelector(".fluxia-messages");
|
|
62
172
|
if (config.initialMessage) {
|
|
63
|
-
|
|
173
|
+
addMsg("assistant", config.initialMessage);
|
|
64
174
|
}
|
|
65
|
-
bubble.addEventListener("click", () =>
|
|
66
|
-
closeBtn.addEventListener("click", () =>
|
|
67
|
-
sendBtn.addEventListener("click",
|
|
175
|
+
bubble.addEventListener("click", () => open());
|
|
176
|
+
closeBtn.addEventListener("click", () => close());
|
|
177
|
+
sendBtn.addEventListener("click", send);
|
|
68
178
|
input.addEventListener("keydown", (e) => {
|
|
69
179
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
70
180
|
e.preventDefault();
|
|
71
|
-
|
|
181
|
+
send();
|
|
72
182
|
}
|
|
73
183
|
});
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
184
|
+
function open() {
|
|
185
|
+
bubble.classList.add("fw-hidden");
|
|
186
|
+
chatbox.classList.add("fw-open");
|
|
187
|
+
setTimeout(() => input.focus(), 350);
|
|
188
|
+
}
|
|
189
|
+
function close() {
|
|
190
|
+
chatbox.classList.remove("fw-open");
|
|
191
|
+
setTimeout(() => bubble.classList.remove("fw-hidden"), 300);
|
|
78
192
|
}
|
|
79
|
-
function
|
|
193
|
+
function addMsg(role, content) {
|
|
80
194
|
const div = document.createElement("div");
|
|
81
195
|
div.className = `fluxia-msg fluxia-msg-${role}`;
|
|
82
196
|
div.textContent = content;
|
|
83
|
-
|
|
84
|
-
|
|
197
|
+
messages.appendChild(div);
|
|
198
|
+
messages.scrollTop = messages.scrollHeight;
|
|
85
199
|
}
|
|
86
|
-
async function
|
|
200
|
+
async function send() {
|
|
87
201
|
const text = input.value.trim();
|
|
88
202
|
if (!text) return;
|
|
89
203
|
input.value = "";
|
|
90
204
|
input.disabled = true;
|
|
91
205
|
sendBtn.disabled = true;
|
|
92
|
-
|
|
206
|
+
addMsg("user", text);
|
|
207
|
+
const loader = document.createElement("div");
|
|
208
|
+
loader.className = "fluxia-msg fluxia-msg-assistant";
|
|
209
|
+
loader.innerHTML = '<div class="fluxia-typing"><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div></div>';
|
|
210
|
+
messages.appendChild(loader);
|
|
211
|
+
messages.scrollTop = messages.scrollHeight;
|
|
93
212
|
try {
|
|
94
213
|
const result = await api.sendMessage(token, text);
|
|
214
|
+
loader.remove();
|
|
95
215
|
if (result.reply) {
|
|
96
|
-
|
|
216
|
+
addMsg("assistant", result.reply.content);
|
|
97
217
|
}
|
|
98
218
|
} catch (err) {
|
|
219
|
+
loader.remove();
|
|
99
220
|
if (err.status === 401) {
|
|
100
|
-
|
|
221
|
+
addMsg("system", "Sessão expirada. Recarregue a página.");
|
|
101
222
|
} else {
|
|
102
|
-
|
|
223
|
+
addMsg("system", "Erro ao enviar mensagem. Tente novamente.");
|
|
103
224
|
}
|
|
104
225
|
console.error("[Fluxia]", err);
|
|
105
226
|
} finally {
|
|
@@ -109,47 +230,7 @@ const renderWidget = ({ config, token, api, visitorId, botId }) => {
|
|
|
109
230
|
}
|
|
110
231
|
}
|
|
111
232
|
};
|
|
112
|
-
function getWidgetHTML({ botName }) {
|
|
113
|
-
return `
|
|
114
|
-
<div id="fluxia-bubble" class="fluxia-bubble" aria-label="Abrir chat" role="button">
|
|
115
|
-
💬
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<div id="fluxia-chatbox" class="fluxia-chatbox" role="dialog" aria-live="polite">
|
|
119
|
-
<div class="fluxia-header">
|
|
120
|
-
<div class="fluxia-header-info">
|
|
121
|
-
<div class="fluxia-avatar">🤖</div>
|
|
122
|
-
<div>
|
|
123
|
-
<div class="fluxia-title">${botName}</div>
|
|
124
|
-
<div class="fluxia-status">Online</div>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
<button id="fluxia-close" class="fluxia-close" aria-label="Fechar">✕</button>
|
|
128
|
-
</div>
|
|
129
|
-
|
|
130
|
-
<div id="fluxia-messages" class="fluxia-messages"></div>
|
|
131
|
-
|
|
132
|
-
<div class="fluxia-input-area">
|
|
133
|
-
<input id="fluxia-input" class="fluxia-input" type="text" placeholder="Digite sua mensagem..." />
|
|
134
|
-
<button id="fluxia-send" class="fluxia-send">Enviar</button>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
`;
|
|
138
|
-
}
|
|
139
|
-
const cssText = '/* Estilos do widget Fluxia — injetados inline no bundle */\r\n\r\n.fluxia-widget {\r\n --fluxia-primary: #dc2626;\r\n --fluxia-radius: 16px;\r\n --fluxia-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);\r\n --fluxia-text: #0f172a;\r\n --fluxia-muted: #64748b;\r\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\r\n}\r\n\r\n.fluxia-widget * {\r\n box-sizing: border-box;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n\r\n.fluxia-bubble {\r\n position: fixed;\r\n bottom: 20px;\r\n z-index: 99999;\r\n width: 56px;\r\n height: 56px;\r\n border-radius: 50%;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);\r\n font-size: 24px;\r\n transition: transform 0.2s;\r\n}\r\n\r\n.fluxia-bubble:hover {\r\n transform: scale(1.1);\r\n}\r\n\r\n.fluxia-chatbox {\r\n display: none;\r\n position: fixed;\r\n bottom: 90px;\r\n z-index: 99999;\r\n width: 370px;\r\n height: 520px;\r\n border-radius: var(--fluxia-radius);\r\n background: #fff;\r\n box-shadow: var(--fluxia-shadow);\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.fluxia-widget[data-position="left"] .fluxia-bubble,\r\n.fluxia-widget[data-position="left"] .fluxia-chatbox {\r\n left: 20px;\r\n right: auto;\r\n}\r\n\r\n.fluxia-widget[data-position="right"] .fluxia-bubble,\r\n.fluxia-widget[data-position="right"] .fluxia-chatbox {\r\n right: 20px;\r\n left: auto;\r\n}\r\n\r\n.fluxia-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 16px;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n}\r\n\r\n.fluxia-header-info {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-avatar {\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background: rgba(255, 255, 255, 0.2);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 16px;\r\n}\r\n\r\n.fluxia-title {\r\n font-weight: 600;\r\n font-size: 14px;\r\n}\r\n\r\n.fluxia-status {\r\n font-size: 11px;\r\n opacity: 0.8;\r\n}\r\n\r\n.fluxia-close {\r\n background: none;\r\n border: none;\r\n color: #fff;\r\n font-size: 20px;\r\n cursor: pointer;\r\n padding: 4px;\r\n}\r\n\r\n.fluxia-messages {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input-area {\r\n padding: 12px;\r\n border-top: 1px solid #e5e7eb;\r\n display: flex;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input {\r\n flex: 1;\r\n border: 1px solid #d1d5db;\r\n border-radius: 8px;\r\n padding: 8px 12px;\r\n font-size: 13px;\r\n outline: none;\r\n}\r\n\r\n.fluxia-send {\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border: none;\r\n border-radius: 8px;\r\n padding: 8px 14px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n font-weight: 600;\r\n}\r\n\r\n.fluxia-msg {\r\n max-width: 80%;\r\n padding: 10px 14px;\r\n border-radius: 12px;\r\n font-size: 13px;\r\n line-height: 1.5;\r\n word-wrap: break-word;\r\n}\r\n\r\n.fluxia-msg-user {\r\n align-self: flex-end;\r\n background: #f1f5f9;\r\n color: #1e293b;\r\n border-bottom-right-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-assistant {\r\n align-self: flex-start;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border-bottom-left-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-system {\r\n align-self: center;\r\n background: #fef3c7;\r\n color: #92400e;\r\n font-size: 12px;\r\n border-radius: 8px;\r\n text-align: center;\r\n}\r\n';
|
|
140
233
|
const VISITOR_ID_KEY = "fluxia_visitor_id";
|
|
141
|
-
const STYLE_TAG_ID = "fluxia-widget-styles";
|
|
142
|
-
const injectStyles = () => {
|
|
143
|
-
if (document.getElementById(STYLE_TAG_ID)) return;
|
|
144
|
-
if (!cssText.trim()) {
|
|
145
|
-
console.warn("[Fluxia] CSS nao carregado. Verifique o build.");
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const style = document.createElement("style");
|
|
149
|
-
style.id = STYLE_TAG_ID;
|
|
150
|
-
style.textContent = cssText;
|
|
151
|
-
document.head.appendChild(style);
|
|
152
|
-
};
|
|
153
234
|
const getVisitorId = () => {
|
|
154
235
|
let id = null;
|
|
155
236
|
try {
|
|
@@ -193,7 +274,6 @@ const getScriptConfig = () => {
|
|
|
193
274
|
const init = async () => {
|
|
194
275
|
const config = getScriptConfig();
|
|
195
276
|
if (!config) return;
|
|
196
|
-
injectStyles();
|
|
197
277
|
const visitorId = getVisitorId();
|
|
198
278
|
const api = createWidgetAPI(config.apiBase);
|
|
199
279
|
try {
|
|
@@ -225,7 +305,7 @@ const init = async () => {
|
|
|
225
305
|
if (!botConfig) {
|
|
226
306
|
botConfig = await api.getConfig(token);
|
|
227
307
|
}
|
|
228
|
-
renderWidget({
|
|
308
|
+
await renderWidget({
|
|
229
309
|
config: botConfig,
|
|
230
310
|
token,
|
|
231
311
|
api,
|
package/dist/chatbot.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(n){"function"==typeof define&&define.amd?define(n):n()}(function(){"use strict";const n='/* Estilos do widget Fluxia — injetados inline no bundle */\r\n\r\n.fluxia-widget {\r\n --fluxia-primary: #dc2626;\r\n --fluxia-radius: 16px;\r\n --fluxia-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);\r\n --fluxia-text: #0f172a;\r\n --fluxia-muted: #64748b;\r\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\r\n}\r\n\r\n.fluxia-widget * {\r\n box-sizing: border-box;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n\r\n.fluxia-bubble {\r\n position: fixed;\r\n bottom: 20px;\r\n z-index: 99999;\r\n width: 56px;\r\n height: 56px;\r\n border-radius: 50%;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);\r\n font-size: 24px;\r\n transition: transform 0.2s;\r\n}\r\n\r\n.fluxia-bubble:hover {\r\n transform: scale(1.1);\r\n}\r\n\r\n.fluxia-chatbox {\r\n display: none;\r\n position: fixed;\r\n bottom: 90px;\r\n z-index: 99999;\r\n width: 370px;\r\n height: 520px;\r\n border-radius: var(--fluxia-radius);\r\n background: #fff;\r\n box-shadow: var(--fluxia-shadow);\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.fluxia-widget[data-position="left"] .fluxia-bubble,\r\n.fluxia-widget[data-position="left"] .fluxia-chatbox {\r\n left: 20px;\r\n right: auto;\r\n}\r\n\r\n.fluxia-widget[data-position="right"] .fluxia-bubble,\r\n.fluxia-widget[data-position="right"] .fluxia-chatbox {\r\n right: 20px;\r\n left: auto;\r\n}\r\n\r\n.fluxia-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 14px 16px;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n}\r\n\r\n.fluxia-header-info {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-avatar {\r\n width: 32px;\r\n height: 32px;\r\n border-radius: 50%;\r\n background: rgba(255, 255, 255, 0.2);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 16px;\r\n}\r\n\r\n.fluxia-title {\r\n font-weight: 600;\r\n font-size: 14px;\r\n}\r\n\r\n.fluxia-status {\r\n font-size: 11px;\r\n opacity: 0.8;\r\n}\r\n\r\n.fluxia-close {\r\n background: none;\r\n border: none;\r\n color: #fff;\r\n font-size: 20px;\r\n cursor: pointer;\r\n padding: 4px;\r\n}\r\n\r\n.fluxia-messages {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input-area {\r\n padding: 12px;\r\n border-top: 1px solid #e5e7eb;\r\n display: flex;\r\n gap: 8px;\r\n}\r\n\r\n.fluxia-input {\r\n flex: 1;\r\n border: 1px solid #d1d5db;\r\n border-radius: 8px;\r\n padding: 8px 12px;\r\n font-size: 13px;\r\n outline: none;\r\n}\r\n\r\n.fluxia-send {\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border: none;\r\n border-radius: 8px;\r\n padding: 8px 14px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n font-weight: 600;\r\n}\r\n\r\n.fluxia-msg {\r\n max-width: 80%;\r\n padding: 10px 14px;\r\n border-radius: 12px;\r\n font-size: 13px;\r\n line-height: 1.5;\r\n word-wrap: break-word;\r\n}\r\n\r\n.fluxia-msg-user {\r\n align-self: flex-end;\r\n background: #f1f5f9;\r\n color: #1e293b;\r\n border-bottom-right-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-assistant {\r\n align-self: flex-start;\r\n background: var(--fluxia-primary);\r\n color: #fff;\r\n border-bottom-left-radius: 4px;\r\n}\r\n\r\n.fluxia-msg-system {\r\n align-self: center;\r\n background: #fef3c7;\r\n color: #92400e;\r\n font-size: 12px;\r\n border-radius: 8px;\r\n text-align: center;\r\n}\r\n',r="fluxia_visitor_id",e="fluxia-widget-styles",i=async()=>{const i=(()=>{const n=document.currentScript||document.querySelector("script[data-bot-id]");if(!n)return console.error("[Fluxia] Script tag não encontrada. Use data-bot-id e data-public-key."),null;const r=n.getAttribute("data-bot-id"),e=n.getAttribute("data-public-key"),i=n.getAttribute("data-client-id"),t=n.getAttribute("data-api-base")||"";return t&&(i||r&&e)?{botId:r?Number(r):null,publicKey:e||"",clientId:i||"",apiBase:t.replace(/\/$/,"")}:(console.error("[Fluxia] Atributos obrigatorios: data-api-base e (data-client-id OU data-bot-id + data-public-key)"),null)})();if(!i)return;(()=>{if(document.getElementById(e))return;if(!n.trim())return void console.warn("[Fluxia] CSS nao carregado. Verifique o build.");const r=document.createElement("style");r.id=e,r.textContent=n,document.head.appendChild(r)})();const t=(()=>{let n=null;try{n=localStorage.getItem(r)}catch{}if(!n){n="v_"+crypto.randomUUID();try{localStorage.setItem(r,n)}catch{}}return n})(),a=(n=>{const r=async(r,e,i=null,t=null)=>{const a={"Content-Type":"application/json"};t&&(a.Authorization=`Bearer ${t}`);const o={method:r,headers:a};i&&(o.body=JSON.stringify(i));const l=await fetch(`${n}${e}`,o);if(!l.ok){const n=await l.json().catch(()=>({})),r=new Error(n.error||`HTTP ${l.status}`);throw r.status=l.status,r.data=n,r}return l.json()};return{bootstrap:({clientId:n,visitorId:e})=>r("POST","/widget/bootstrap",{clientId:n,visitorId:e}),handshake:({botId:n,publicKey:e,visitorId:i})=>r("POST","/widget/handshake",{botId:n,publicKey:e,visitorId:i}),getConfig:n=>r("GET","/widget/config",null,n),sendMessage:(n,e)=>r("POST","/widget/message",{message:e},n),captureLead:(n,e)=>r("POST","/widget/lead",e,n)}})(i.apiBase);try{let n="",r=null;if(i.clientId){const e=await a.bootstrap({clientId:i.clientId,visitorId:t});if(!e||!e.token)return void console.error("[Fluxia] Bootstrap falhou. Widget nao sera renderizado.");n=e.token,r=e.config||null}else{const r=await a.handshake({botId:i.botId,publicKey:i.publicKey,visitorId:t});if(!r||!r.token)return void console.error("[Fluxia] Handshake falhou. Widget nao sera renderizado.");n=r.token}r||(r=await a.getConfig(n)),(({config:n,token:r,api:e,visitorId:i,botId:t})=>{const a=n.theme||{},o=a.primaryColor||"#dc2626",l=a.position||"right",s=n.botName||n.name||"Assistente",d=document.createElement("div");d.id="fluxia-widget-root",d.className="chatbot-scope fluxia-widget",d.dataset.position=l,d.style.setProperty("--fluxia-primary",o),d.innerHTML=function({botName:n}){return`\n <div id="fluxia-bubble" class="fluxia-bubble" aria-label="Abrir chat" role="button">\n 💬\n </div>\n\n <div id="fluxia-chatbox" class="fluxia-chatbox" role="dialog" aria-live="polite">\n <div class="fluxia-header">\n <div class="fluxia-header-info">\n <div class="fluxia-avatar">🤖</div>\n <div>\n <div class="fluxia-title">${n}</div>\n <div class="fluxia-status">Online</div>\n </div>\n </div>\n <button id="fluxia-close" class="fluxia-close" aria-label="Fechar">✕</button>\n </div>\n\n <div id="fluxia-messages" class="fluxia-messages"></div>\n\n <div class="fluxia-input-area">\n <input id="fluxia-input" class="fluxia-input" type="text" placeholder="Digite sua mensagem..." />\n <button id="fluxia-send" class="fluxia-send">Enviar</button>\n </div>\n </div>\n `}({botName:s,initialMessage:n.initialMessage}),document.body.appendChild(d);let u=!1;const c=d.querySelector("#fluxia-bubble"),f=d.querySelector("#fluxia-chatbox"),x=d.querySelector("#fluxia-close"),p=d.querySelector("#fluxia-input"),b=d.querySelector("#fluxia-send"),g=d.querySelector("#fluxia-messages");function m(n){u=n,f.style.display=u?"flex":"none",c.style.display=u?"none":"flex"}function y(n,r){const e=document.createElement("div");e.className=`fluxia-msg fluxia-msg-${n}`,e.textContent=r,g.appendChild(e),g.scrollTop=g.scrollHeight}async function h(){const n=p.value.trim();if(n){p.value="",p.disabled=!0,b.disabled=!0,y("user",n);try{const i=await e.sendMessage(r,n);i.reply&&y("assistant",i.reply.content)}catch(i){401===i.status?y("system","Sessão expirada. Recarregue a página."):y("system","Erro ao enviar mensagem. Tente novamente."),console.error("[Fluxia]",i)}finally{p.disabled=!1,b.disabled=!1,p.focus()}}}n.initialMessage&&y("assistant",n.initialMessage),c.addEventListener("click",()=>m(!0)),x.addEventListener("click",()=>m(!1)),b.addEventListener("click",h),p.addEventListener("keydown",n=>{"Enter"!==n.key||n.shiftKey||(n.preventDefault(),h())})})({config:r,token:n,api:a,visitorId:t,botId:i.botId||(null==r?void 0:r.botId)}),console.log("[Fluxia] Widget inicializado com sucesso.")}catch(o){console.error("[Fluxia] Erro na inicialização:",o.message||o)}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",i):i()});
|
|
1
|
+
!function(t){"function"==typeof define&&define.amd?define(t):t()}(function(){"use strict";const t="fluxia-widget-styles",e=t=>{const e=document.createElement("div");return e.textContent=t,e.innerHTML};const i=async({config:i,token:a,api:o,visitorId:n,botId:r})=>{(()=>{if(document.getElementById(t))return;const e=document.createElement("style");e.id=t,e.textContent='\n#fluxia-widget-root{all:initial;font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;line-height:1.5;color:#1f2937;--fw-header:#0f172a;--fw-white:#fff;--fw-green:#22c55e;--fw-red:#ef4444;--fw-red-dark:#dc2626;--fw-text:#1f2937;--fw-gray-100:#f3f4f6;--fw-gray-200:#e5e7eb;--fw-gray-300:#d1d5db;--fw-gray-bg:#fafbfc;--fw-radius:20px;--fw-shadow:0 20px 60px rgba(0,0,0,.25)}\n#fluxia-widget-root *,#fluxia-widget-root *::before,#fluxia-widget-root *::after{box-sizing:border-box;margin:0;padding:0}\n#fluxia-widget-root .fluxia-bubble{position:fixed;bottom:24px;right:24px;z-index:2147483646;width:60px;height:60px;border-radius:50%;border:none;background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 8px 24px rgba(239,68,68,.5),0 0 0 4px rgba(255,255,255,.25);transition:transform .3s cubic-bezier(.34,1.56,.64,1),box-shadow .3s,opacity .25s;opacity:1}\n#fluxia-widget-root .fluxia-bubble.fw-hidden{transform:scale(0);opacity:0;pointer-events:none}\n#fluxia-widget-root .fluxia-bubble svg{width:28px;height:28px;fill:#fff;stroke:none}\n#fluxia-widget-root .fluxia-chatbox{position:fixed;bottom:10px;right:10px;z-index:2147483647;width:400px;height:600px;max-height:calc(100vh - 120px);border-radius:var(--fw-radius);background:var(--fw-white);box-shadow:var(--fw-shadow);display:flex;flex-direction:column;overflow:hidden;transform-origin:bottom right;transform:scale(0) translateY(20px);opacity:0;pointer-events:none;transition:transform .35s cubic-bezier(.34,1.56,.64,1),opacity .25s}\n#fluxia-widget-root .fluxia-chatbox.fw-open{transform:scale(1) translateY(0);opacity:1;pointer-events:auto}\n#fluxia-widget-root .fluxia-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;background:var(--fw-header);color:var(--fw-white);flex-shrink:0;border-radius:var(--fw-radius) var(--fw-radius) 0 0}\n#fluxia-widget-root .fluxia-header-info{display:flex;align-items:center;gap:12px;flex:1;min-width:0}\n#fluxia-widget-root .fluxia-avatar{width:42px;height:42px;min-width:42px;border-radius:50%;background:rgba(255,255,255,.12);border:2px solid rgba(34,197,94,.5);display:flex;align-items:center;justify-content:center;font-size:20px;overflow:hidden;color:#fff}\n#fluxia-widget-root .fluxia-avatar img{width:100%;height:100%;object-fit:cover;border-radius:50%}\n#fluxia-widget-root .fluxia-header-text{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}\n#fluxia-widget-root .fluxia-title{font-weight:700;font-size:15px;color:var(--fw-white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n#fluxia-widget-root .fluxia-status{font-size:12px;color:var(--fw-green);display:flex;align-items:center;gap:6px;font-weight:600}\n#fluxia-widget-root .fluxia-status-dot{width:7px;height:7px;border-radius:50%;background:var(--fw-green);display:inline-block;animation:fw-pulse 2s ease-in-out infinite}\n@keyframes fw-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.3)}}\n#fluxia-widget-root .fluxia-close{width:34px;height:34px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.08);border:none;color:var(--fw-white);cursor:pointer;border-radius:8px;transition:background .2s}\n#fluxia-widget-root .fluxia-close:hover{background:rgba(255,255,255,.18)}\n#fluxia-widget-root .fluxia-close svg{width:16px;height:16px}\n#fluxia-widget-root .fluxia-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;background:var(--fw-white)}\n#fluxia-widget-root .fluxia-msg{max-width:82%;padding:10px 14px;font-size:13.5px;line-height:1.55;word-wrap:break-word;overflow-wrap:break-word;animation:fw-msgIn .3s ease-out}\n@keyframes fw-msgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n#fluxia-widget-root .fluxia-msg-assistant{align-self:flex-start;background:var(--fw-gray-100);color:var(--fw-text);border-radius:16px 16px 16px 4px}\n#fluxia-widget-root .fluxia-msg-user{align-self:flex-end;background:var(--fw-header);color:var(--fw-white);border-radius:16px 16px 4px 16px}\n#fluxia-widget-root .fluxia-msg-system{align-self:center;background:#fef3c7;color:#92400e;font-size:12px;padding:8px 14px;border-radius:8px;text-align:center;max-width:90%;border:1px solid #fde68a}\n#fluxia-widget-root .fluxia-typing{display:flex;gap:5px;align-items:center;padding:4px 0}\n#fluxia-widget-root .fluxia-typing-dot{width:7px;height:7px;border-radius:50%;background:#94a3b8;animation:fw-bounce 1.4s infinite ease-in-out}\n#fluxia-widget-root .fluxia-typing-dot:nth-child(2){animation-delay:.16s}\n#fluxia-widget-root .fluxia-typing-dot:nth-child(3){animation-delay:.32s}\n@keyframes fw-bounce{0%,80%,100%{transform:scale(.7);opacity:.4}40%{transform:scale(1.1);opacity:1}}\n#fluxia-widget-root .fluxia-input-area{padding:12px 14px;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);display:flex;align-items:center;gap:10px;flex-shrink:0}\n#fluxia-widget-root .fluxia-input{flex:1;border:1.5px solid var(--fw-gray-300);border-radius:24px;padding:10px 16px;font-size:13px;font-family:inherit;outline:none;color:var(--fw-text);background:var(--fw-gray-bg);transition:border-color .2s,box-shadow .2s}\n#fluxia-widget-root .fluxia-input::placeholder{color:#9ca3af}\n#fluxia-widget-root .fluxia-input:focus{border-color:var(--fw-header);background:var(--fw-white);box-shadow:0 0 0 3px rgba(15,23,42,.06)}\n#fluxia-widget-root .fluxia-input:disabled{opacity:.5;cursor:not-allowed}\n#fluxia-widget-root .fluxia-send{width:40px;height:40px;min-width:40px;border-radius:50%;background:var(--fw-red);color:var(--fw-white);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .2s,transform .2s;flex-shrink:0}\n#fluxia-widget-root .fluxia-send:hover{background:var(--fw-red-dark);transform:scale(1.08)}\n#fluxia-widget-root .fluxia-send:active{transform:scale(.92)}\n#fluxia-widget-root .fluxia-send:disabled{opacity:.4;cursor:not-allowed;transform:none}\n#fluxia-widget-root .fluxia-send svg{width:18px;height:18px}\n#fluxia-widget-root .fluxia-powered{text-align:center;padding:8px 0;font-size:11px;color:#9ca3af;background:var(--fw-white);border-top:1px solid var(--fw-gray-200);flex-shrink:0}\n#fluxia-widget-root .fluxia-powered a{color:#6b7280;text-decoration:none;font-weight:600}\n#fluxia-widget-root[data-position="left"] .fluxia-bubble{left:24px;right:auto}\n#fluxia-widget-root[data-position="left"] .fluxia-chatbox{left:24px;right:auto;transform-origin:bottom left}\n@media(max-width:768px){#fluxia-widget-root .fluxia-chatbox{width:calc(100vw - 32px);max-width:400px;height:calc(100vh - 140px);max-height:600px;bottom:10px;right:10px}#fluxia-widget-root .fluxia-bubble{bottom:20px;right:16px;width:56px;height:56px}}\n@media(max-width:480px){#fluxia-widget-root .fluxia-chatbox{position:fixed;top:0;left:0;right:0;bottom:0;width:100%;height:100%;max-width:none;max-height:none;border-radius:0;transform-origin:bottom center}#fluxia-widget-root .fluxia-chatbox.fw-open{border-radius:0}#fluxia-widget-root .fluxia-header{border-radius:0}#fluxia-widget-root .fluxia-bubble{bottom:16px;right:16px;width:52px;height:52px}#fluxia-widget-root .fluxia-bubble svg{width:24px;height:24px}#fluxia-widget-root .fluxia-avatar{width:38px;height:38px;min-width:38px}#fluxia-widget-root .fluxia-title{font-size:14px}#fluxia-widget-root .fluxia-msg{max-width:88%;font-size:13px}#fluxia-widget-root .fluxia-input{font-size:14px}#fluxia-widget-root .fluxia-send{width:38px;height:38px;min-width:38px}}\n',document.head.appendChild(e)})();const l=(i.theme||{}).position||"right",d=i.botName||i.name||"Assistente",s=i.botAvatar||"",f=i.customCss||"",u=document.createElement("div");if(u.id="fluxia-widget-root",u.dataset.position=l,u.innerHTML=function({botName:t,botAvatar:i}){return`\n <button class="fluxia-bubble" aria-label="Abrir chat" title="Abrir chat">\n <svg viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>\n </button>\n\n <div class="fluxia-chatbox" role="dialog" aria-label="Chat">\n <div class="fluxia-header">\n <div class="fluxia-header-info">\n <div class="fluxia-avatar">${i?`<img src="${e(i)}" alt="Avatar" />`:"🤖"}</div>\n <div class="fluxia-header-text">\n <div class="fluxia-title">${t}</div>\n <div class="fluxia-status">\n <span class="fluxia-status-dot"></span>\n Online agora\n </div>\n </div>\n </div>\n <button class="fluxia-close" aria-label="Fechar chat" title="Fechar">\n <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">\n <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>\n </svg>\n </button>\n </div>\n\n <div class="fluxia-messages"></div>\n\n <div class="fluxia-input-area">\n <input class="fluxia-input" type="text"\n placeholder="Pergunte sobre leads, métricas ou integrações"\n autocomplete="off" />\n <button class="fluxia-send" title="Enviar">\n <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"\n stroke-linecap="round" stroke-linejoin="round">\n <line x1="22" y1="2" x2="11" y2="13"/>\n <polygon points="22 2 15 22 11 13 2 9 22 2"/>\n </svg>\n </button>\n </div>\n\n <div class="fluxia-powered">\n Powered by <a href="https://rowsky.com.br/" target="_blank" rel="noopener">Rowsky</a>\n </div>\n </div>\n `}({botName:e(d),botAvatar:s}),document.body.appendChild(u),f&&f.trim()){const t=document.createElement("style");t.id="fluxia-widget-custom",t.textContent=f,document.head.appendChild(t)}const x=u.querySelector(".fluxia-bubble"),c=u.querySelector(".fluxia-chatbox"),p=u.querySelector(".fluxia-close"),g=u.querySelector(".fluxia-input"),w=u.querySelector(".fluxia-send"),h=u.querySelector(".fluxia-messages");function b(t,e){const i=document.createElement("div");i.className=`fluxia-msg fluxia-msg-${t}`,i.textContent=e,h.appendChild(i),h.scrollTop=h.scrollHeight}async function m(){const t=g.value.trim();if(!t)return;g.value="",g.disabled=!0,w.disabled=!0,b("user",t);const e=document.createElement("div");e.className="fluxia-msg fluxia-msg-assistant",e.innerHTML='<div class="fluxia-typing"><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div><div class="fluxia-typing-dot"></div></div>',h.appendChild(e),h.scrollTop=h.scrollHeight;try{const i=await o.sendMessage(a,t);e.remove(),i.reply&&b("assistant",i.reply.content)}catch(i){e.remove(),401===i.status?b("system","Sessão expirada. Recarregue a página."):b("system","Erro ao enviar mensagem. Tente novamente."),console.error("[Fluxia]",i)}finally{g.disabled=!1,w.disabled=!1,g.focus()}}i.initialMessage&&b("assistant",i.initialMessage),x.addEventListener("click",()=>(x.classList.add("fw-hidden"),c.classList.add("fw-open"),void setTimeout(()=>g.focus(),350))),p.addEventListener("click",()=>(c.classList.remove("fw-open"),void setTimeout(()=>x.classList.remove("fw-hidden"),300))),w.addEventListener("click",m),g.addEventListener("keydown",t=>{"Enter"!==t.key||t.shiftKey||(t.preventDefault(),m())})},a="fluxia_visitor_id",o=async()=>{const t=(()=>{const t=document.currentScript||document.querySelector("script[data-bot-id]");if(!t)return console.error("[Fluxia] Script tag não encontrada. Use data-bot-id e data-public-key."),null;const e=t.getAttribute("data-bot-id"),i=t.getAttribute("data-public-key"),a=t.getAttribute("data-client-id"),o=t.getAttribute("data-api-base")||"";return o&&(a||e&&i)?{botId:e?Number(e):null,publicKey:i||"",clientId:a||"",apiBase:o.replace(/\/$/,"")}:(console.error("[Fluxia] Atributos obrigatorios: data-api-base e (data-client-id OU data-bot-id + data-public-key)"),null)})();if(!t)return;const e=(()=>{let t=null;try{t=localStorage.getItem(a)}catch{}if(!t){t="v_"+crypto.randomUUID();try{localStorage.setItem(a,t)}catch{}}return t})(),o=(t=>{const e=async(e,i,a=null,o=null)=>{const n={"Content-Type":"application/json"};o&&(n.Authorization=`Bearer ${o}`);const r={method:e,headers:n};a&&(r.body=JSON.stringify(a));const l=await fetch(`${t}${i}`,r);if(!l.ok){const t=await l.json().catch(()=>({})),e=new Error(t.error||`HTTP ${l.status}`);throw e.status=l.status,e.data=t,e}return l.json()};return{bootstrap:({clientId:t,visitorId:i})=>e("POST","/widget/bootstrap",{clientId:t,visitorId:i}),handshake:({botId:t,publicKey:i,visitorId:a})=>e("POST","/widget/handshake",{botId:t,publicKey:i,visitorId:a}),getConfig:t=>e("GET","/widget/config",null,t),sendMessage:(t,i)=>e("POST","/widget/message",{message:i},t),captureLead:(t,i)=>e("POST","/widget/lead",i,t)}})(t.apiBase);try{let a="",n=null;if(t.clientId){const i=await o.bootstrap({clientId:t.clientId,visitorId:e});if(!i||!i.token)return void console.error("[Fluxia] Bootstrap falhou. Widget nao sera renderizado.");a=i.token,n=i.config||null}else{const i=await o.handshake({botId:t.botId,publicKey:t.publicKey,visitorId:e});if(!i||!i.token)return void console.error("[Fluxia] Handshake falhou. Widget nao sera renderizado.");a=i.token}n||(n=await o.getConfig(a)),await i({config:n,token:a,api:o,visitorId:e,botId:t.botId||(null==n?void 0:n.botId)}),console.log("[Fluxia] Widget inicializado com sucesso.")}catch(n){console.error("[Fluxia] Erro na inicialização:",n.message||n)}};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",o):o()});
|