@mobil80-dev/chatbot-widget 1.0.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -17
- package/index.js +105 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,33 +4,60 @@ A lightweight JavaScript chatbot widget powered by VaultChat, designed to be emb
|
|
|
4
4
|
|
|
5
5
|
## ✨ Features
|
|
6
6
|
|
|
7
|
-
- Floating chat button
|
|
7
|
+
- Floating chat button (fully customizable)
|
|
8
8
|
- Chat card UI
|
|
9
|
-
- API-based chatbot responses
|
|
10
|
-
-
|
|
11
|
-
- No
|
|
9
|
+
- API-based chatbot responses
|
|
10
|
+
- Light & Dark theme support
|
|
11
|
+
- No iframe
|
|
12
|
+
- No dependencies
|
|
12
13
|
- Easy setup
|
|
13
14
|
|
|
14
15
|
## 📦 Installation
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
```bash
|
|
16
18
|
npm install @mobil80-dev/chatbot-widget
|
|
17
19
|
```
|
|
18
20
|
|
|
21
|
+
## 🎨 Theme (Light / Dark)
|
|
22
|
+
|
|
23
|
+
VaultChat supports light and dark themes to match your application UI.
|
|
24
|
+
This helps improve text visibility and appearance when used inside dark-themed websites.
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
theme: 'light' | 'dark'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## ✅ Supported Button Types
|
|
31
|
+
|
|
32
|
+
You can use emoji, text, image, or custom HTML as the floating button.
|
|
33
|
+
|
|
34
|
+
## ✅ Supported Button Shapes
|
|
35
|
+
|
|
36
|
+
You can use circle, square, pill as the floating button shape.
|
|
37
|
+
|
|
19
38
|
## 🌐 HTML / CSS
|
|
39
|
+
|
|
20
40
|
### 🚀 Usage
|
|
41
|
+
|
|
21
42
|
```
|
|
22
43
|
<script type="module">
|
|
23
44
|
import VaultChat from 'https://unpkg.com/@mobil80-dev/chatbot-widget/dist/index.js'
|
|
24
45
|
|
|
25
46
|
VaultChat.init({
|
|
26
47
|
apiKey: 'YOUR_API_KEY',
|
|
27
|
-
primaryColor: '#7c3aed'
|
|
48
|
+
primaryColor: '#7c3aed',
|
|
49
|
+
theme: 'light' | 'dark'
|
|
50
|
+
buttonContent: '💬', // content | image Url | emote
|
|
51
|
+
buttonType: 'emoji', // emoji | text | image | html
|
|
52
|
+
buttonShape: 'circle' // circle | square | pill
|
|
28
53
|
})
|
|
29
54
|
</script>
|
|
30
55
|
```
|
|
31
56
|
|
|
32
57
|
## 🧩 Vue
|
|
58
|
+
|
|
33
59
|
### 🚀 Usage (Vue 3)
|
|
60
|
+
|
|
34
61
|
```
|
|
35
62
|
import { onMounted } from 'vue'
|
|
36
63
|
import VaultChat from '@mobil80-dev/chatbot-widget'
|
|
@@ -38,21 +65,31 @@ import VaultChat from '@mobil80-dev/chatbot-widget'
|
|
|
38
65
|
onMounted(() => {
|
|
39
66
|
VaultChat.init({
|
|
40
67
|
apiKey: 'YOUR_API_KEY',
|
|
41
|
-
primaryColor: '#7c3aed'
|
|
68
|
+
primaryColor: '#7c3aed',
|
|
69
|
+
theme: 'light' | 'dark'
|
|
70
|
+
buttonContent: '💬', // content | image Url | emote
|
|
71
|
+
buttonType: 'emoji', // emoji | text | image | html
|
|
72
|
+
buttonShape: 'circle' // circle | square | pill
|
|
42
73
|
})
|
|
43
74
|
})
|
|
44
75
|
```
|
|
76
|
+
|
|
45
77
|
## ⚛️ React
|
|
46
78
|
|
|
47
79
|
### 🚀 Usage
|
|
48
|
-
|
|
80
|
+
|
|
81
|
+
```
|
|
49
82
|
import { useEffect } from 'react'
|
|
50
83
|
import VaultChat from '@mobil80-dev/chatbot-widget'
|
|
51
84
|
|
|
52
85
|
useEffect(() => {
|
|
53
86
|
VaultChat.init({
|
|
54
87
|
apiKey: 'YOUR_API_KEY',
|
|
55
|
-
primaryColor: '#7c3aed'
|
|
88
|
+
primaryColor: '#7c3aed',
|
|
89
|
+
theme: 'light' | 'dark'
|
|
90
|
+
buttonContent: '💬', // content | image Url | emote
|
|
91
|
+
buttonType: 'emoji', // emoji | text | image | html
|
|
92
|
+
buttonShape: 'circle' // circle | square | pill
|
|
56
93
|
})
|
|
57
94
|
}, [])
|
|
58
95
|
```
|
|
@@ -60,29 +97,41 @@ useEffect(() => {
|
|
|
60
97
|
## 🅰️ Angular
|
|
61
98
|
|
|
62
99
|
### 🚀 Usage
|
|
63
|
-
|
|
100
|
+
|
|
101
|
+
```
|
|
64
102
|
import VaultChat from '@mobil80-dev/chatbot-widget'
|
|
65
103
|
|
|
66
104
|
VaultChat.init({
|
|
67
105
|
apiKey: 'YOUR_API_KEY',
|
|
68
|
-
primaryColor: '#7c3aed'
|
|
106
|
+
primaryColor: '#7c3aed',
|
|
107
|
+
theme: 'light' | 'dark'
|
|
108
|
+
buttonContent: '💬', // content | image Url | emote
|
|
109
|
+
buttonType: 'emoji', // emoji | text | image | html
|
|
110
|
+
buttonShape: 'circle' // circle | square | pill
|
|
69
111
|
})
|
|
70
112
|
|
|
71
113
|
```
|
|
72
114
|
|
|
73
|
-
|
|
74
115
|
📌 Call this inside ngOnInit() of your root or layout component.
|
|
75
116
|
|
|
76
|
-
## ⚙️ Configuration
|
|
117
|
+
## ⚙️ Configuration Reference
|
|
118
|
+
|
|
77
119
|
```
|
|
78
|
-
Option
|
|
79
|
-
|
|
80
|
-
|
|
120
|
+
| Option | Type | Description |
|
|
121
|
+
| ------------- | ------ | ----------------------------------- |
|
|
122
|
+
| apiKey | string | Your VaultChat API key |
|
|
123
|
+
| primaryColor | string | Primary UI color |
|
|
124
|
+
| theme | string | `light` or `dark` |
|
|
125
|
+
| buttonContent | string | Emoji, text, image URL, or HTML |
|
|
126
|
+
| buttonType | string | `emoji` | `text` | `image` | `html` |
|
|
127
|
+
| buttonShape | string | `circle` | `square` | `pill` |
|
|
128
|
+
|
|
81
129
|
|
|
82
130
|
```
|
|
131
|
+
|
|
83
132
|
## 📄 License
|
|
84
133
|
|
|
85
134
|
```
|
|
86
135
|
MIT
|
|
87
136
|
Mobil80
|
|
88
|
-
```
|
|
137
|
+
```
|
package/index.js
CHANGED
|
@@ -12,67 +12,113 @@ const VaultChat = {
|
|
|
12
12
|
? 'dark'
|
|
13
13
|
: 'light'
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
15
|
+
const isDark = theme === 'dark'
|
|
16
|
+
|
|
17
|
+
const colors = isDark
|
|
18
|
+
? {
|
|
19
|
+
cardBg: '#0f172a',
|
|
20
|
+
headerBorder: '#1e293b',
|
|
21
|
+
text: '#e5e7eb',
|
|
22
|
+
mutedText: '#94a3b8',
|
|
23
|
+
inputBg: '#020617',
|
|
24
|
+
inputBorder: '#334155',
|
|
25
|
+
botBubble: '#1e293b',
|
|
26
|
+
userText: '#ffffff',
|
|
27
|
+
messagesBg: '#020617'
|
|
28
|
+
}
|
|
29
|
+
: {
|
|
30
|
+
cardBg: '#ffffff',
|
|
31
|
+
headerBorder: '#e5e7eb',
|
|
32
|
+
text: '#0f172a',
|
|
33
|
+
mutedText: '#64748b',
|
|
34
|
+
inputBg: '#ffffff',
|
|
35
|
+
inputBorder: '#cbd5f5',
|
|
36
|
+
botBubble: '#e5e7eb',
|
|
37
|
+
userText: '#ffffff',
|
|
38
|
+
messagesBg: '#f8fafc'
|
|
39
|
+
}
|
|
39
40
|
|
|
40
41
|
const primaryColor = config.primaryColor || '#2563eb'
|
|
42
|
+
let loaderEl = null
|
|
43
|
+
|
|
44
|
+
/* ============================
|
|
45
|
+
LOADER STYLES (Injected once)
|
|
46
|
+
============================ */
|
|
47
|
+
const style = document.createElement('style')
|
|
48
|
+
style.innerHTML = `
|
|
49
|
+
.vc-loader {
|
|
50
|
+
display: inline-flex;
|
|
51
|
+
gap: 6px;
|
|
52
|
+
padding: 8px 12px;
|
|
53
|
+
background: var(--vc-bot-bg);
|
|
54
|
+
border-radius: 12px;
|
|
55
|
+
max-width: 80%;
|
|
56
|
+
margin-bottom: 8px;
|
|
57
|
+
}
|
|
58
|
+
.vc-loader span {
|
|
59
|
+
width: 6px;
|
|
60
|
+
height: 6px;
|
|
61
|
+
background: var(--vc-text-muted);
|
|
62
|
+
border-radius: 50%;
|
|
63
|
+
animation: vc-bounce 1.4s infinite ease-in-out both;
|
|
64
|
+
}
|
|
65
|
+
.vc-loader span:nth-child(1) { animation-delay: -0.32s; }
|
|
66
|
+
.vc-loader span:nth-child(2) { animation-delay: -0.16s; }
|
|
67
|
+
|
|
68
|
+
@keyframes vc-bounce {
|
|
69
|
+
0%, 80%, 100% { transform: scale(0); }
|
|
70
|
+
40% { transform: scale(1); }
|
|
71
|
+
}
|
|
72
|
+
`
|
|
73
|
+
document.head.appendChild(style)
|
|
41
74
|
|
|
42
75
|
/* ============================
|
|
43
76
|
FLOATING BUTTON
|
|
44
77
|
============================ */
|
|
45
78
|
const button = document.createElement('div')
|
|
79
|
+
const buttonContent = config.buttonContent || '🤖'
|
|
80
|
+
const buttonType = config.buttonType || 'emoji'
|
|
81
|
+
const buttonShape = config.buttonShape || 'circle'
|
|
46
82
|
|
|
47
|
-
if (
|
|
48
|
-
button.innerHTML = config.buttonHtml
|
|
49
|
-
} else if (config.buttonIconUrl) {
|
|
83
|
+
if (buttonType === 'image') {
|
|
50
84
|
const img = document.createElement('img')
|
|
51
|
-
img.src =
|
|
85
|
+
img.src = buttonContent
|
|
52
86
|
img.style.width = '26px'
|
|
53
87
|
img.style.height = '26px'
|
|
54
88
|
img.style.objectFit = 'contain'
|
|
55
89
|
button.appendChild(img)
|
|
56
|
-
} else if (
|
|
57
|
-
button.
|
|
90
|
+
} else if (buttonType === 'html') {
|
|
91
|
+
button.innerHTML = buttonContent
|
|
58
92
|
} else {
|
|
59
|
-
button.textContent =
|
|
93
|
+
button.textContent = buttonContent
|
|
60
94
|
}
|
|
61
95
|
|
|
96
|
+
let borderRadius = '50%'
|
|
97
|
+
if (buttonShape === 'square') borderRadius = '8px'
|
|
98
|
+
if (buttonShape === 'pill') borderRadius = '999px'
|
|
99
|
+
|
|
100
|
+
const isTextButton = buttonType === 'text'
|
|
101
|
+
|
|
62
102
|
Object.assign(button.style, {
|
|
63
103
|
position: 'fixed',
|
|
64
104
|
bottom: '20px',
|
|
65
105
|
right: '20px',
|
|
66
|
-
width: '56px',
|
|
67
|
-
height: '56px',
|
|
68
|
-
|
|
106
|
+
width: isTextButton ? 'auto' : '56px',
|
|
107
|
+
height: isTextButton ? 'auto' : '56px',
|
|
108
|
+
padding: isTextButton ? '10px 16px' : '0',
|
|
109
|
+
minWidth: '56px',
|
|
110
|
+
minHeight: '56px',
|
|
111
|
+
borderRadius,
|
|
69
112
|
background: primaryColor,
|
|
70
113
|
color: '#fff',
|
|
71
114
|
display: 'flex',
|
|
72
115
|
alignItems: 'center',
|
|
73
116
|
justifyContent: 'center',
|
|
74
117
|
cursor: 'pointer',
|
|
75
|
-
fontSize: '
|
|
118
|
+
fontSize: '18px',
|
|
119
|
+
fontWeight: '500',
|
|
120
|
+
boxShadow: '0 8px 20px rgba(0,0,0,.25)',
|
|
121
|
+
userSelect: 'none',
|
|
76
122
|
zIndex: 999999
|
|
77
123
|
})
|
|
78
124
|
|
|
@@ -80,7 +126,6 @@ const VaultChat = {
|
|
|
80
126
|
CHAT CARD
|
|
81
127
|
============================ */
|
|
82
128
|
const card = document.createElement('div')
|
|
83
|
-
|
|
84
129
|
card.innerHTML = `
|
|
85
130
|
<div style="
|
|
86
131
|
padding:12px;
|
|
@@ -143,6 +188,9 @@ const VaultChat = {
|
|
|
143
188
|
flexDirection: 'column'
|
|
144
189
|
})
|
|
145
190
|
|
|
191
|
+
card.style.setProperty('--vc-bot-bg', colors.botBubble)
|
|
192
|
+
card.style.setProperty('--vc-text-muted', colors.mutedText)
|
|
193
|
+
|
|
146
194
|
let open = false
|
|
147
195
|
button.onclick = () => {
|
|
148
196
|
open = !open
|
|
@@ -173,6 +221,21 @@ const VaultChat = {
|
|
|
173
221
|
messages.scrollTop = messages.scrollHeight
|
|
174
222
|
}
|
|
175
223
|
|
|
224
|
+
function showLoader () {
|
|
225
|
+
loaderEl = document.createElement('div')
|
|
226
|
+
loaderEl.className = 'vc-loader'
|
|
227
|
+
loaderEl.innerHTML = '<span></span><span></span><span></span>'
|
|
228
|
+
messages.appendChild(loaderEl)
|
|
229
|
+
messages.scrollTop = messages.scrollHeight
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function hideLoader () {
|
|
233
|
+
if (loaderEl) {
|
|
234
|
+
loaderEl.remove()
|
|
235
|
+
loaderEl = null
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
176
239
|
function addBotMessage (text) {
|
|
177
240
|
const div = document.createElement('div')
|
|
178
241
|
div.style.cssText = `
|
|
@@ -194,14 +257,13 @@ const VaultChat = {
|
|
|
194
257
|
addUserMessage(text)
|
|
195
258
|
input.value = ''
|
|
196
259
|
|
|
197
|
-
// 🔐 API key missing → internal response only
|
|
198
260
|
if (!config.apiKey) {
|
|
199
|
-
addBotMessage(
|
|
200
|
-
'⚠️ API key not configured. Please add apiKey in VaultChat.init().'
|
|
201
|
-
)
|
|
261
|
+
addBotMessage('⚠️ API key not configured. Please add apiKey.')
|
|
202
262
|
return
|
|
203
263
|
}
|
|
204
264
|
|
|
265
|
+
showLoader()
|
|
266
|
+
|
|
205
267
|
try {
|
|
206
268
|
const res = await fetch('https://api.vaultchat.io/askChatbot', {
|
|
207
269
|
method: 'POST',
|
|
@@ -213,12 +275,15 @@ const VaultChat = {
|
|
|
213
275
|
})
|
|
214
276
|
|
|
215
277
|
const data = await res.json()
|
|
278
|
+
hideLoader()
|
|
279
|
+
|
|
216
280
|
const reply =
|
|
217
281
|
data?.data?.blocks?.map(b => b.text).join('\n') ||
|
|
218
282
|
'No response received'
|
|
219
283
|
|
|
220
284
|
addBotMessage(reply)
|
|
221
285
|
} catch {
|
|
286
|
+
hideLoader()
|
|
222
287
|
addBotMessage('⚠️ Something went wrong')
|
|
223
288
|
}
|
|
224
289
|
}
|