@quidgest/chatbot 0.1.0 → 0.2.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/dist/style.css CHANGED
@@ -1 +1 @@
1
- .svg-icon[data-v-695796d5]{display:inline-flex;width:16px;height:14px}.svg-icon[data-v-695796d5] svg{width:100%;height:100%}.q-chatbot{width:100%;padding:1rem;display:flex;flex-direction:column;height:100%}.q-chatbot input{line-height:1.5rem}.q-chatbot .q-input-group .i-text__field{border-radius:0;flex:1}.q-chatbot__content{background-color:#fff;border:1px solid #eaebec;height:100%;width:100%;display:flex;gap:.75rem;flex-direction:column;overflow:hidden}.q-chatbot__footer-container{padding:.8rem}.q-chatbot__send-container{padding-bottom:.25rem;display:flex;justify-content:space-between;width:100%}.q-chatbot__send-container .q-chatbot__send,.q-chatbot__send-container .q-chatbot__upload{border-radius:1rem}.q-chatbot__send-container .spacer{flex-grow:1}.q-chatbot__footer{position:sticky;padding:0 .5rem;border:1px solid #eaebec;border-radius:.25rem;bottom:0;width:100%;display:flex;flex-direction:column;gap:.25rem}.q-chatbot__footer-disabled{background-color:rgb(var(--q-theme-neutral-light-rgb)/.25);cursor:not-allowed}.q-chatbot__footer .q-chatbot__input{min-height:50px;max-height:100px;border-bottom:1px solid #eaebec;overflow-y:auto}.q-chatbot__footer .q-text-area{max-height:100%;overflow-y:auto}.q-chatbot__footer .q-text-area .q-field__control{border:none}.q-chatbot__upload-container{display:flex;justify-content:flex-start;padding:.25rem 0}.q-chatbot__upload-container .q-chatbot__upload{border-radius:1rem}.q-chatbot__messages-container{display:flex;flex-direction:column;flex-grow:1;padding:0 1rem 2rem;gap:1.5rem;overflow-y:auto}.q-chatbot__messages-wrapper{display:flex;max-width:100%;gap:.2rem}.q-chatbot__tools{display:flex;flex-direction:row;justify-content:end;max-width:100%}.q-chatbot__message-wrapper{display:flex;flex-direction:column;gap:.2rem}.q-chatbot__message-container{display:flex;flex-direction:column;gap:.25rem}.q-chatbot__messages-wrapper_right{justify-content:flex-end}.q-chatbot__messages-wrapper_right .q-chatbot__message-container{align-items:flex-end}.q-chatbot__messages-wrapper_right .q-chatbot__message-wrapper{display:flex;align-items:flex-end}.q-chatbot__profile.q-icon__img{border-radius:50%;height:2rem;width:2rem}.q-chatbot__message{display:flex;align-items:center;padding:.3rem .5rem;background-color:#eaebec;width:fit-content;white-space:normal;min-height:2rem;word-wrap:break-word;word-break:break-word;border-radius:0 .5rem .5rem}.q-chatbot__messages-wrapper_right .q-chatbot__message{background-color:#018bd233;border-radius:.5rem 0 .5rem .5rem}.q-chatbot__sender{white-space:nowrap;color:#7c858d;font-size:.7rem}.q-chatbot__retry-button{align-items:center;display:flex}.q-chatbot__image-preview{position:relative;display:inline-block}.q-chatbot__image-preview img{max-height:100px;width:auto;border-radius:8px;margin:10px 0}.q-chatbot__remove-image{position:absolute;top:5px;right:5px;background-color:#00000080;color:#fff;border-radius:50%;padding:5px;cursor:pointer;font-size:12px;border:none}.hidden-input{display:none}.pulsing-dots{display:flex;align-items:center;justify-content:center;gap:.1rem}.dot{font-size:20px;line-height:1;animation:pulse 1s infinite;color:var(--q-theme-primary)}@keyframes pulse{0%,to{transform:scale(.8);opacity:.6}50%{transform:scale(1);opacity:1}}
1
+ .q-chatbot{width:100%;padding:1rem;display:flex;flex-direction:column;height:100%}.q-chatbot input{line-height:1.5rem}.q-chatbot .q-input-group .i-text__field{border-radius:0;flex:1}.q-chatbot__text p{margin:0}.q-chatbot__content{background-color:#fff;border:1px solid #eaebec;height:100%;width:100%;display:flex;gap:.75rem;flex-direction:column;overflow:hidden}.q-chatbot__footer-container{padding:.8rem}.q-chatbot__input-wrapper{display:flex;flex-direction:column;position:relative}.q-chatbot__image-preview{display:inline-flex;align-items:center;position:relative;margin-top:.5rem;width:fit-content}.q-chatbot__image-preview img{width:60px;height:60px;object-fit:cover;border-radius:4px;margin-right:.25rem;border:1px solid #eaebec;overflow:hidden}.q-chatbot__image-preview img:hover+.q-chatbot__remove-image,.q-chatbot__image-preview img:focus+.q-chatbot__remove-image{opacity:1;pointer-events:auto}.q-chatbot__image-preview img:focus{outline:solid rgb(var(--q-theme-info-rgb)/50%)}.q-chatbot .q-btn.q-chatbot__remove-image{position:absolute;top:-5px;right:-5px;background-color:#00000080;color:#fff;border-radius:50%;padding:5px;font-size:12px;border:none;opacity:0;pointer-events:none;transition:opacity .2s ease-in-out}.q-chatbot .q-btn.q-chatbot__remove-image:hover,.q-chatbot .q-btn.q-chatbot__remove-image:focus{opacity:1;pointer-events:auto}.q-chatbot__send-container{padding-bottom:.25rem;display:flex;justify-content:space-between;width:100%}.q-chatbot__send-container .q-chatbot__send,.q-chatbot__send-container .q-chatbot__upload{border-radius:1rem}.q-chatbot__send-container .spacer{flex-grow:1}.q-chatbot__footer{position:sticky;padding:0 .5rem;border:1px solid #eaebec;border-radius:.25rem;bottom:0;width:100%;display:flex;flex-direction:column;gap:.25rem}.q-chatbot__footer-disabled{background-color:rgb(var(--q-theme-neutral-light-rgb)/.25);cursor:not-allowed}.q-chatbot__footer.drag-over{border:2px dashed rgb(var(--q-theme-primary-rgb)/.25);background-color:#018bd20d}.q-chatbot__footer .q-chatbot__input{min-height:50px;max-height:100px;border-bottom:1px solid #eaebec;overflow-y:auto}.q-chatbot__footer .q-text-area{max-height:100%;overflow-y:auto}.q-chatbot__footer .q-text-area .q-field__control{border:none}.q-chatbot__upload-container{display:flex;justify-content:flex-start;padding:.25rem 0}.q-chatbot__upload-container .q-chatbot__upload{border-radius:1rem}.q-chatbot__messages-container{display:flex;flex-direction:column;flex-grow:1;padding:0 1rem 2rem;gap:1.5rem;overflow-y:auto}.q-chatbot__messages-wrapper{display:flex;max-width:100%;gap:.2rem}.q-chatbot__tools{display:flex;flex-direction:row;justify-content:end;max-width:100%}.q-chatbot__message-wrapper{display:flex;flex-direction:column;gap:.2rem}.q-chatbot__message-container{display:flex;flex-direction:column;gap:.25rem}.q-chatbot__messages-wrapper_right{justify-content:flex-end}.q-chatbot__messages-wrapper_right .q-chatbot__message-container{align-items:flex-end}.q-chatbot__messages-wrapper_right .q-chatbot__message-wrapper{display:flex;align-items:flex-end}.q-chatbot__profile.q-icon__img{border-radius:50%;height:2rem;width:2rem}.q-chatbot__message{display:flex;align-items:center;padding:.3rem .5rem;background-color:#eaebec;width:fit-content;white-space:normal;min-height:2rem;word-wrap:break-word;word-break:break-word;border-radius:0 .5rem .5rem}.q-chatbot__messages-wrapper_right .q-chatbot__message{background-color:#018bd233;border-radius:.5rem 0 .5rem .5rem}.q-chatbot__sender{white-space:nowrap;color:#7c858d;font-size:.7rem}.q-chatbot__retry-button{align-items:center;display:flex}.q-chatbot__dialog-title{margin:.5rem 0}#comment-dialog .q-dialog__header,.hidden-input{display:none}.pulsing-dots{display:flex;align-items:center;justify-content:center;gap:.1rem}.dot{font-size:20px;line-height:1;animation:pulse 1s infinite;color:var(--q-theme-primary)}@keyframes pulse{0%,to{transform:scale(.8);opacity:.6}50%{transform:scale(1);opacity:1}}
@@ -14,3 +14,21 @@ export type ChatBotMessageContent = {
14
14
  imageUrl?: string;
15
15
  };
16
16
  export type ChatBotMessageSender = 'bot' | 'user';
17
+ export interface CBMessageProps {
18
+ sender?: ChatBotMessageSender;
19
+ message?: string;
20
+ date?: Date;
21
+ loading?: boolean;
22
+ /**
23
+ * Project locale
24
+ */
25
+ dateFormat?: string;
26
+ /**
27
+ * User image
28
+ */
29
+ userImage: string;
30
+ /**
31
+ * Chatbot image
32
+ */
33
+ chatbotImage: string;
34
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quidgest/chatbot",
3
3
  "private": false,
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
7
7
  "main": "dist/index.cjs",
@@ -32,12 +32,14 @@
32
32
  "lint:fix": "eslint . --fix && prettier --write --list-different src"
33
33
  },
34
34
  "dependencies": {
35
- "axios": "^1.6.7",
36
- "uuid": "^11.0.5"
35
+ "axios": "^1.7.0",
36
+ "uuid": "^11.1.0",
37
+ "vue-markdown-render": "^2.2.1"
37
38
  },
38
39
  "devDependencies": {
39
- "@types/node": "^20.16.1",
40
- "@vitejs/plugin-vue": "^4.6.2",
40
+ "@types/markdown-it": "^14.1.2",
41
+ "@types/node": "^20.11.13",
42
+ "@vitejs/plugin-vue": "^4.5.2",
41
43
  "eslint": "^9.9.0",
42
44
  "eslint-plugin-prettier": "^5.2.1",
43
45
  "prettier": "^3.3.3",
@@ -15,6 +15,12 @@
15
15
  flex: 1;
16
16
  }
17
17
 
18
+ &__text {
19
+ p {
20
+ margin: 0;
21
+ }
22
+ }
23
+
18
24
  &__content {
19
25
  background-color: white;
20
26
  border: 1px solid #eaebec;
@@ -27,13 +33,70 @@
27
33
  overflow: hidden;
28
34
  }
29
35
 
30
-
31
36
  &__footer-container {
32
37
  padding: 0.8rem;
33
38
  }
34
39
 
40
+ &__input-wrapper {
41
+ display: flex;
42
+ flex-direction: column;
43
+ position: relative;
44
+ }
45
+
46
+ &__image-preview {
47
+ display: inline-flex;
48
+ align-items: center;
49
+ position: relative;
50
+ margin-top: 0.5rem;
51
+ width: fit-content;
52
+
53
+ img {
54
+ width: 60px;
55
+ height: 60px;
56
+ object-fit: cover;
57
+ border-radius: 4px;
58
+ margin-right: 0.25rem;
59
+ border: 1px solid #eaebec;
60
+ overflow: hidden;
61
+
62
+ &:hover,
63
+ &:focus {
64
+
65
+ & + .q-chatbot__remove-image {
66
+ opacity: 1;
67
+ pointer-events: auto;
68
+ }
69
+ }
70
+
71
+ &:focus {
72
+ outline: solid rgb(var(--q-theme-info-rgb) / 50%);
73
+ }
74
+ }
75
+ }
76
+
77
+ .q-btn.q-chatbot__remove-image {
78
+ position: absolute;
79
+ top: -5px;
80
+ right: -5px;
81
+ background-color: rgba(0, 0, 0, 0.5);
82
+ color: white;
83
+ border-radius: 50%;
84
+ padding: 5px;
85
+ font-size: 12px;
86
+ border: none;
87
+ opacity: 0;
88
+ pointer-events: none;
89
+ transition: opacity 0.2s ease-in-out;
90
+
91
+ &:hover,
92
+ &:focus {
93
+ opacity: 1;
94
+ pointer-events: auto;
95
+ }
96
+ }
97
+
35
98
  &__send-container {
36
- padding-bottom: .25rem;
99
+ padding-bottom: 0.25rem;
37
100
  display: flex;
38
101
  justify-content: space-between;
39
102
  width: 100%;
@@ -53,20 +116,25 @@
53
116
 
54
117
  &__footer {
55
118
  position: sticky;
56
- padding: 0 .5rem;
119
+ padding: 0 0.5rem;
57
120
  border: 1px solid #eaebec;
58
- border-radius: .25rem;
121
+ border-radius: 0.25rem;
59
122
  bottom: 0;
60
123
  width: 100%;
61
124
  display: flex;
62
125
  flex-direction: column;
63
- gap: .25rem;
126
+ gap: 0.25rem;
64
127
 
65
128
  &-disabled {
66
129
  background-color: rgb(var(--q-theme-neutral-light-rgb) / 0.25);
67
130
  cursor: not-allowed;
68
131
  }
69
132
 
133
+ &.drag-over {
134
+ border: 2px dashed rgb(var(--q-theme-primary-rgb) / 0.25);
135
+ background-color: rgba(1, 139, 210, 0.05);
136
+ }
137
+
70
138
  & .q-chatbot__input {
71
139
  min-height: 50px;
72
140
  max-height: 100px;
@@ -87,8 +155,8 @@
87
155
  &__upload-container {
88
156
  display: flex;
89
157
  justify-content: flex-start;
90
- padding: .25rem 0;
91
-
158
+ padding: 0.25rem 0;
159
+
92
160
  & .q-chatbot__upload {
93
161
  border-radius: 1rem;
94
162
  }
@@ -180,29 +248,14 @@
180
248
  display: flex;
181
249
  }
182
250
 
183
- &__image-preview {
184
- position: relative;
185
- display: inline-block;
186
-
187
- img {
188
- max-height: 100px;
189
- width: auto;
190
- border-radius: 8px;
191
- margin: 10px 0;
192
- }
251
+ &__dialog-title{
252
+ margin: 0.5rem 0;
193
253
  }
254
+ }
194
255
 
195
- &__remove-image {
196
- position: absolute;
197
- top: 5px;
198
- right: 5px;
199
- background-color: rgba(0, 0, 0, 0.5);
200
- color: white;
201
- border-radius: 50%;
202
- padding: 5px;
203
- cursor: pointer;
204
- font-size: 12px;
205
- border: none;
256
+ #comment-dialog {
257
+ .q-dialog__header {
258
+ display: none;
206
259
  }
207
260
  }
208
261
 
@@ -225,12 +278,13 @@
225
278
  }
226
279
 
227
280
  @keyframes pulse {
228
- 0%, 100% {
229
- transform: scale(0.8);
230
- opacity: 0.6;
281
+ 0%,
282
+ 100% {
283
+ transform: scale(0.8);
284
+ opacity: 0.6;
231
285
  }
232
286
  50% {
233
- transform: scale(1);
234
- opacity: 1;
287
+ transform: scale(1);
288
+ opacity: 1;
235
289
  }
236
- }
290
+ }
@@ -1,6 +1,5 @@
1
1
  <template>
2
2
  <div class="q-chatbot__message-container">
3
- <!-- Chatbot Image -->
4
3
  <q-icon
5
4
  type="img"
6
5
  :icon="messageImage"
@@ -20,22 +19,26 @@
20
19
  <!-- When loading is true, show bouncing dots animation -->
21
20
  <pulse-dots v-if="loading" />
22
21
  <template v-else>
23
- <div
24
- class="q-chatbot__text"
22
+ <vue-markdown-render
25
23
  v-if="props.sender === 'bot'"
26
- v-html="props.message"></div>
27
- <div
28
24
  class="q-chatbot__text"
29
- v-else>
25
+ :source="props.message || ''" />
26
+
27
+ <div
28
+ v-else
29
+ class="q-chatbot__text">
30
30
  {{ props.message }}
31
31
  </div>
32
32
  </template>
33
33
  </div>
34
34
  <q-dialog
35
+ id="comment-dialog"
35
36
  v-model="showDialog"
36
- :buttons="commentButtons"
37
- :text="props.texts.commentDialogTitle">
38
- <template #body.append>
37
+ :buttons="commentButtons">
38
+ <template #body.content>
39
+ <div class="q-chatbot__dialog-title">
40
+ {{ props.texts.commentDialogTitle }}
41
+ </div>
39
42
  <q-text-field
40
43
  v-model="feedbackComment"
41
44
  :maxLength="150"
@@ -55,7 +58,7 @@
55
58
  :disabled="loading"
56
59
  b-style="secondary"
57
60
  @click="openFeedbackDialog(1)">
58
- <span v-html="thumbUpSvg" class="svg-icon"></span>
61
+ <q-icon icon="thumb-up" />
59
62
  </q-button>
60
63
  <q-button
61
64
  :title="props.texts.badResponse"
@@ -63,7 +66,7 @@
63
66
  :disabled="loading"
64
67
  b-style="secondary"
65
68
  @click="openFeedbackDialog(0)">
66
- <span v-html="thumbDownSvg" class="svg-icon"></span>
69
+ <q-icon icon="thumb-down" />
67
70
  </q-button>
68
71
  <q-button
69
72
  :title="props.texts.copyResponse"
@@ -71,7 +74,7 @@
71
74
  :disabled="loading"
72
75
  b-style="secondary"
73
76
  @click="copyResponse">
74
- <span v-html="copySvg" class="svg-icon"></span>
77
+ <q-icon icon="copy-content" />
75
78
  </q-button>
76
79
  </q-button-group>
77
80
  </div>
@@ -93,17 +96,8 @@
93
96
  import PulseDots from '@/components/PulseDots.vue'
94
97
  import type { ChatBotMessageSender } from '@/types/message.type'
95
98
  import { ResourceStrings } from '@/types/texts.type'
99
+ import VueMarkdownRender from 'vue-markdown-render'
96
100
  import Axios from 'axios'
97
-
98
- // Importando o conteúdo dos arquivos SVG como strings
99
- import thumbUpSvgFile from '@/assets/thumbUp.svg?raw'
100
- import thumbDownSvgFile from '@/assets/thumbDown.svg?raw'
101
- import copySvgFile from '@/assets/copy.svg?raw'
102
-
103
- // Armazenando o conteúdo SVG como strings
104
- const thumbUpSvg = thumbUpSvgFile;
105
- const thumbDownSvg = thumbDownSvgFile;
106
- const copySvg = copySvgFile;
107
101
 
108
102
  export interface CBMessageProps {
109
103
  /*
@@ -160,7 +154,7 @@
160
154
  * Chatbot image
161
155
  */
162
156
  chatbotImage: string
163
-
157
+
164
158
  /**
165
159
  * Flag to mark welcome messages
166
160
  */
@@ -193,36 +187,40 @@
193
187
  action: submitFeedback,
194
188
  props: {
195
189
  label: props.texts.submitButton,
196
- 'b-style': 'primary'
190
+ 'b-style': 'primary',
191
+ },
192
+ icon: {
193
+ icon: 'submit'
197
194
  }
198
195
  },
199
196
  {
200
197
  id: 'cancel-btn',
201
198
  props: {
202
199
  label: props.texts.cancelButton,
203
- 'b-style': 'danger'
200
+ 'b-style': 'secondary',
201
+ },
202
+ icon: {
203
+ icon: 'cancel'
204
204
  }
205
205
  }
206
206
  ]
207
207
 
208
- const senderName = computed(() => {
209
- return props.sender === 'bot' ? 'GenioBot' : 'You'
210
- })
211
-
212
208
  const isBotMessageAndNotDefault = computed(() => {
213
- return props.sender === 'bot' &&
209
+ return (
210
+ props.sender === 'bot' &&
214
211
  !Object.values(props.texts || {}).includes(props.message || '') &&
215
212
  !props.isWelcomeMessage
213
+ )
216
214
  })
217
215
 
218
216
  const getLocaleDate = computed(() => {
219
217
  if (!props.dateFormat) return props.date.toLocaleString()
220
218
 
221
- return formatDate(props.date, props.dateFormat)
219
+ return formatDate(props.date, 'HH:mm')
222
220
  })
223
221
 
224
222
  const messageDate = computed(() => {
225
- return `${senderName.value} ${getLocaleDate.value}`
223
+ return `${getLocaleDate.value}`
226
224
  })
227
225
 
228
226
  const messageImage = computed(() =>
@@ -276,24 +274,7 @@
276
274
  console.log('Message copied to clipboard')
277
275
  })
278
276
  .catch((error) => {
279
- console.error(
280
- 'Failed to copy message to clipboard: ',
281
- error
282
- )
277
+ console.error('Failed to copy message to clipboard: ', error)
283
278
  })
284
279
  }
285
280
  </script>
286
-
287
- <style scoped>
288
-
289
- .svg-icon {
290
- display: inline-flex;
291
- width: 16px;
292
- height: 14px;
293
- }
294
-
295
- .svg-icon :deep(svg) {
296
- width: 100%;
297
- height: 100%;
298
- }
299
- </style>