@mobil80-dev/chatbot-widget 1.0.8 → 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.
Files changed (3) hide show
  1. package/README.md +66 -17
  2. package/index.js +163 -27
  3. package/package.json +5 -2
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
- - No iframe
11
- - No dependencies
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
- ``` bash
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 Type Description
79
- apiKey string Your VaultChat API key
80
- primaryColor string Primary UI theme color
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
@@ -1,46 +1,154 @@
1
1
  const VaultChat = {
2
2
  init (config = {}) {
3
+ /* ============================
4
+ THEME RESOLUTION
5
+ ============================ */
6
+ const theme =
7
+ config.theme === 'dark'
8
+ ? 'dark'
9
+ : config.theme === 'light'
10
+ ? 'light'
11
+ : window.matchMedia('(prefers-color-scheme: dark)').matches
12
+ ? 'dark'
13
+ : 'light'
14
+
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
+ }
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)
74
+
75
+ /* ============================
76
+ FLOATING BUTTON
77
+ ============================ */
3
78
  const button = document.createElement('div')
4
- button.innerHTML = '💬'
79
+ const buttonContent = config.buttonContent || '🤖'
80
+ const buttonType = config.buttonType || 'emoji'
81
+ const buttonShape = config.buttonShape || 'circle'
82
+
83
+ if (buttonType === 'image') {
84
+ const img = document.createElement('img')
85
+ img.src = buttonContent
86
+ img.style.width = '26px'
87
+ img.style.height = '26px'
88
+ img.style.objectFit = 'contain'
89
+ button.appendChild(img)
90
+ } else if (buttonType === 'html') {
91
+ button.innerHTML = buttonContent
92
+ } else {
93
+ button.textContent = buttonContent
94
+ }
95
+
96
+ let borderRadius = '50%'
97
+ if (buttonShape === 'square') borderRadius = '8px'
98
+ if (buttonShape === 'pill') borderRadius = '999px'
99
+
100
+ const isTextButton = buttonType === 'text'
5
101
 
6
102
  Object.assign(button.style, {
7
103
  position: 'fixed',
8
104
  bottom: '20px',
9
105
  right: '20px',
10
- width: '56px',
11
- height: '56px',
12
- borderRadius: '50%',
13
- background: config.primaryColor || '#2563eb',
106
+ width: isTextButton ? 'auto' : '56px',
107
+ height: isTextButton ? 'auto' : '56px',
108
+ padding: isTextButton ? '10px 16px' : '0',
109
+ minWidth: '56px',
110
+ minHeight: '56px',
111
+ borderRadius,
112
+ background: primaryColor,
14
113
  color: '#fff',
15
114
  display: 'flex',
16
115
  alignItems: 'center',
17
116
  justifyContent: 'center',
18
117
  cursor: 'pointer',
19
- fontSize: '24px',
20
- zIndex: 9999
118
+ fontSize: '18px',
119
+ fontWeight: '500',
120
+ boxShadow: '0 8px 20px rgba(0,0,0,.25)',
121
+ userSelect: 'none',
122
+ zIndex: 999999
21
123
  })
22
124
 
125
+ /* ============================
126
+ CHAT CARD
127
+ ============================ */
23
128
  const card = document.createElement('div')
24
129
  card.innerHTML = `
25
- <div style="padding:12px;border-bottom:1px solid #eee">
26
- <div style="
27
- text-align:left;
28
- font-size:14px;
29
- color:#94a3b8;
30
- user-select:none;
31
- opacity:0.8">
32
- Powered by <strong>VaultChat</strong>
33
- </div>
130
+ <div style="
131
+ padding:12px;
132
+ border-bottom:1px solid ${colors.headerBorder};
133
+ color:${colors.mutedText};
134
+ font-size:14px;
135
+ user-select:none">
136
+ Powered by <strong>VaultChat</strong>
34
137
  </div>
35
138
 
36
139
  <div id="vc-messages" style="
37
140
  flex:1;
38
141
  padding:12px;
39
142
  overflow-y:auto;
40
- background:#f8fafc">
143
+ background:${colors.messagesBg};
144
+ color:${colors.text}">
41
145
  </div>
42
146
 
43
- <div style="display:flex;padding:10px;border-top:1px solid #eee">
147
+ <div style="
148
+ display:flex;
149
+ padding:10px;
150
+ border-top:1px solid ${colors.headerBorder};
151
+ background:${colors.cardBg}">
44
152
  <input
45
153
  id="vc-input"
46
154
  placeholder="Type your message..."
@@ -48,7 +156,9 @@ const VaultChat = {
48
156
  flex:1;
49
157
  padding:10px;
50
158
  border-radius:8px;
51
- border:1px solid #ccc;
159
+ border:1px solid ${colors.inputBorder};
160
+ background:${colors.inputBg};
161
+ color:${colors.text};
52
162
  outline:none"
53
163
  />
54
164
  <button id="vc-send" style="
@@ -56,7 +166,7 @@ const VaultChat = {
56
166
  padding:0 14px;
57
167
  border:none;
58
168
  border-radius:8px;
59
- background:${config.primaryColor || '#2563eb'};
169
+ background:${primaryColor};
60
170
  color:white;
61
171
  cursor:pointer">
62
172
 
@@ -70,14 +180,17 @@ const VaultChat = {
70
180
  right: '20px',
71
181
  width: '400px',
72
182
  height: '420px',
73
- background: '#fff',
183
+ background: colors.cardBg,
74
184
  borderRadius: '12px',
75
185
  boxShadow: '0 10px 30px rgba(0,0,0,.3)',
76
- zIndex: 9999,
186
+ zIndex: 999999,
77
187
  display: 'none',
78
188
  flexDirection: 'column'
79
189
  })
80
190
 
191
+ card.style.setProperty('--vc-bot-bg', colors.botBubble)
192
+ card.style.setProperty('--vc-text-muted', colors.mutedText)
193
+
81
194
  let open = false
82
195
  button.onclick = () => {
83
196
  open = !open
@@ -87,6 +200,9 @@ const VaultChat = {
87
200
  document.body.appendChild(button)
88
201
  document.body.appendChild(card)
89
202
 
203
+ /* ============================
204
+ CHAT LOGIC
205
+ ============================ */
90
206
  const messages = card.querySelector('#vc-messages')
91
207
  const input = card.querySelector('#vc-input')
92
208
  const sendBtn = card.querySelector('#vc-send')
@@ -94,8 +210,8 @@ const VaultChat = {
94
210
  function addUserMessage (text) {
95
211
  const div = document.createElement('div')
96
212
  div.style.cssText = `
97
- background:${config.primaryColor || '#2563eb'};
98
- color:white;
213
+ background:${primaryColor};
214
+ color:${colors.userText};
99
215
  padding:8px 12px;
100
216
  border-radius:12px;
101
217
  max-width:80%;
@@ -105,10 +221,26 @@ const VaultChat = {
105
221
  messages.scrollTop = messages.scrollHeight
106
222
  }
107
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
+
108
239
  function addBotMessage (text) {
109
240
  const div = document.createElement('div')
110
241
  div.style.cssText = `
111
- background:#e5e7eb;
242
+ background:${colors.botBubble};
243
+ color:${colors.text};
112
244
  padding:8px 12px;
113
245
  border-radius:12px;
114
246
  max-width:80%;
@@ -125,12 +257,13 @@ const VaultChat = {
125
257
  addUserMessage(text)
126
258
  input.value = ''
127
259
 
128
- // ✅ apiKey not configured → internal message only
129
260
  if (!config.apiKey) {
130
- addBotMessage('⚠️ API key not configured. Please add apiKey in VaultChat.init()')
261
+ addBotMessage('⚠️ API key not configured. Please add apiKey.')
131
262
  return
132
263
  }
133
264
 
265
+ showLoader()
266
+
134
267
  try {
135
268
  const res = await fetch('https://api.vaultchat.io/askChatbot', {
136
269
  method: 'POST',
@@ -142,12 +275,15 @@ const VaultChat = {
142
275
  })
143
276
 
144
277
  const data = await res.json()
278
+ hideLoader()
279
+
145
280
  const reply =
146
281
  data?.data?.blocks?.map(b => b.text).join('\n') ||
147
282
  'No response received'
148
283
 
149
284
  addBotMessage(reply)
150
285
  } catch {
286
+ hideLoader()
151
287
  addBotMessage('⚠️ Something went wrong')
152
288
  }
153
289
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobil80-dev/chatbot-widget",
3
- "version": "1.0.8",
3
+ "version": "2.0.0",
4
4
  "description": "Drop-in JavaScript chat widget for websites (no iframe, no framework)",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -12,5 +12,8 @@
12
12
  "vaultchat"
13
13
  ],
14
14
  "author": "Nantha Gopal",
15
- "license": "MIT"
15
+ "license": "MIT",
16
+ "dependencies": {
17
+ "@mobil80-dev/chatbot-widget": "^1.0.8"
18
+ }
16
19
  }