rio-assist-widget 0.1.28 → 0.1.32

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.
@@ -1,198 +1,176 @@
1
- import { html } from 'lit';
2
- import { unsafeHTML } from 'lit/directives/unsafe-html.js';
3
- import { classMap } from 'lit/directives/class-map.js';
4
- import type { RioAssistWidget } from '../rio-assist/rio-assist';
5
- import { renderConversationsPanel } from '../conversations-panel/conversations-panel.template';
6
-
7
- const hamburgerIconUrl = new URL('../../assets/icons/hamburgerMenuIcon.png', import.meta.url).href;
8
- const expandIconUrl = new URL('../../assets/icons/expandScreen.png', import.meta.url).href;
9
- const iaCentralIconUrl = new URL('../../assets/icons/iaCentralIcon.png', import.meta.url).href;
10
- const plusFileSelectionUrl = new URL('../../assets/icons/plusFileSelection.png', import.meta.url).href;
11
- const closeIconUrl = new URL('../../assets/icons/closeIcon.png', import.meta.url).href;
12
- const arrowButtonUrl = new URL('../../assets/icons/arrowButton.png', import.meta.url).href;
13
-
14
- export const renderChatSurface = (component: RioAssistWidget) => {
15
- const hasMessages = component.messages.length > 0;
16
-
1
+ import { html } from 'lit';
2
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
3
+ import { classMap } from 'lit/directives/class-map.js';
4
+ import type { RioAssistWidget } from '../rio-assist/rio-assist';
5
+ import { renderConversationsPanel } from '../conversations-panel/conversations-panel.template';
6
+
7
+ const hamburgerIconUrl = new URL('../../assets/icons/hamburgerMenuIcon.png', import.meta.url).href;
8
+ const expandIconUrl = new URL('../../assets/icons/expandScreen.png', import.meta.url).href;
9
+ const iaCentralIconUrl = new URL('../../assets/icons/iaCentralIcon.png', import.meta.url).href;
10
+ const plusFileSelectionUrl = new URL('../../assets/icons/plusFileSelection.png', import.meta.url).href;
11
+ const closeIconUrl = new URL('../../assets/icons/closeIcon.png', import.meta.url).href;
12
+ const arrowButtonUrl = new URL('../../assets/icons/arrowButton.png', import.meta.url).href;
13
+
14
+ export const renderChatSurface = (component: RioAssistWidget) => {
15
+ const hasMessages = component.messages.length > 0;
16
+
17
17
  const heroCard = html`
18
18
  <div class="hero-card">
19
19
  <img src=${iaCentralIconUrl} alt="IA assistente" class="hero-card__icon" />
20
20
  <h3>Como posso te ajudar hoje?</h3>
21
- <button
22
- type="button"
23
- class="short-answer-toggle short-answer-toggle--hero"
24
- role="switch"
25
- aria-checked=${component.shortAnswerEnabled}
26
- @click=${() => component.toggleShortAnswers()}
27
- >
28
- <span
29
- class=${classMap({
30
- 'short-answer-toggle__track': true,
31
- 'short-answer-toggle__track--on': component.shortAnswerEnabled,
32
- })}
33
- aria-hidden="true"
34
- >
35
- <span class="short-answer-toggle__thumb"></span>
36
- </span>
37
- <span class="short-answer-toggle__label">Ativar respostas curtas</span>
38
- </button>
39
- </div>
40
- `;
41
-
42
- const conversation = html`
43
- <div class="conversation">
44
- ${component.messages.map(
45
- (message) => html`
46
- <div
47
- class=${classMap({
48
- message: true,
49
- 'message--user': message.role === 'user',
50
- 'message--assistant': message.role === 'assistant',
51
- })}
52
- >
53
- <div class="message__content">
54
- ${unsafeHTML(message.html ?? message.text)}
55
- </div>
56
- <time>
57
- ${new Date(message.timestamp).toLocaleTimeString('pt-BR', {
58
- hour: '2-digit',
59
- minute: '2-digit',
60
- })}
61
- </time>
62
- </div>
63
- `,
64
- )}
65
- ${component.isLoading
66
- ? html`
67
- <div class="message message--assistant typing">
68
- <span>${component.loadingLabel}</span>
69
- <span class="typing__dots" aria-hidden="true">
70
- <span>.</span><span>.</span><span>.</span>
71
- </span>
72
- </div>
73
- `
74
- : null}
75
21
  </div>
76
22
  `;
77
-
78
- return html`
79
- <div class="panel-body">
80
- <div
81
- class=${classMap({
82
- 'panel-content': true,
83
- 'panel-content--empty': !hasMessages,
84
- })}
85
- >
86
- ${hasMessages ? conversation : heroCard}
87
- </div>
88
-
89
- ${component.errorMessage
90
- ? html`<p class="error-banner">${component.errorMessage}</p>`
91
- : null}
92
-
23
+
24
+ const conversation = html`
25
+ <div class="conversation">
26
+ ${component.messages.map(
27
+ (message) => html`
28
+ <div
29
+ class=${classMap({
30
+ message: true,
31
+ 'message--user': message.role === 'user',
32
+ 'message--assistant': message.role === 'assistant',
33
+ })}
34
+ >
35
+ <div class="message__content">
36
+ ${unsafeHTML(message.html ?? message.text)}
37
+ </div>
38
+ <time>
39
+ ${new Date(message.timestamp).toLocaleTimeString('pt-BR', {
40
+ hour: '2-digit',
41
+ minute: '2-digit',
42
+ })}
43
+ </time>
44
+ </div>
45
+ `,
46
+ )}
47
+ ${component.isLoading
48
+ ? html`
49
+ <div class="message message--assistant typing">
50
+ <span>${component.loadingLabel}</span>
51
+ <span class="typing__dots" aria-hidden="true">
52
+ <span>.</span><span>.</span><span>.</span>
53
+ </span>
54
+ </div>
55
+ `
56
+ : null}
57
+ </div>
58
+ `;
59
+
60
+ return html`
61
+ <div class="panel-body">
62
+ <div
63
+ class=${classMap({
64
+ 'panel-content': true,
65
+ 'panel-content--empty': !hasMessages,
66
+ })}
67
+ >
68
+ ${hasMessages ? conversation : heroCard}
69
+ </div>
70
+
71
+ ${component.errorMessage
72
+ ? html`<p class="error-banner">${component.errorMessage}</p>`
73
+ : null}
74
+
93
75
  <div class="panel-footer">
94
- ${hasMessages
95
- ? html`
96
- <button
97
- type="button"
98
- class="short-answer-toggle"
99
- role="switch"
100
- aria-checked=${component.shortAnswerEnabled}
101
- @click=${() => component.toggleShortAnswers()}
102
- >
103
- <span
104
- class=${classMap({
105
- 'short-answer-toggle__track': true,
106
- 'short-answer-toggle__track--on': component.shortAnswerEnabled,
107
- })}
108
- aria-hidden="true"
109
- >
110
- <span class="short-answer-toggle__thumb"></span>
111
- </span>
112
- <span class="short-answer-toggle__label">Ativar respostas curtas</span>
113
- </button>
114
- `
115
- : null}
116
-
117
- ${component.suggestions.length > 0
118
- ? html`
119
- <div class="suggestions-wrapper">
120
- <p class="suggestions-label">Sugestões de Perguntas</p>
121
- <div class="suggestions">
122
- ${component.suggestions.map(
123
- (suggestion) => html`
124
- <button
125
- class="suggestion"
126
- type="button"
127
- @click=${() => component.onSuggestionClick(suggestion)}
128
- >
129
- ${suggestion}
130
- </button>
131
- `,
132
- )}
133
- </div>
134
- </div>
135
- `
136
- : null}
137
-
138
- <form
139
- @submit=${(event: SubmitEvent) => component.handleSubmit(event)}
140
- aria-busy=${component.isLoading}
141
- >
142
- <input
143
- type="text"
144
- placeholder=${component.placeholder}
145
- .value=${component.message}
146
- @input=${(event: InputEvent) => {
147
- component.message = (event.target as HTMLInputElement).value;
148
- }}
149
- ?disabled=${component.isLoading}
150
- />
151
- <button
152
- class="input-button submit-button"
153
- type="submit"
154
- aria-label="Enviar mensagem"
155
- ?disabled=${component.isLoading}
156
- >
157
- <img src=${arrowButtonUrl} alt="" aria-hidden="true" />
158
- </button>
159
- </form>
160
-
161
- <p class="footnote">
162
- IA pode cometer erros. Por isso lembre-se de conferir informacoes importantes.
163
- </p>
164
- </div>
165
- </div>
166
- `;
167
- };
168
-
169
- export const renderMiniPanel = (component: RioAssistWidget) => {
170
- const chatSurface = renderChatSurface(component);
171
-
172
- return html`
173
- <aside class=${classMap({ panel: true, open: component.open })} role="dialog">
174
- <header class="panel-header">
175
- <div class="panel-header__top">
176
- <span class="panel-title">${component.titleText}</span>
177
- <button
178
- class="close-button"
179
- @click=${() => component.handleCloseAction()}
180
- aria-label="Fechar Rio Insight"
181
- >
182
- <img src=${closeIconUrl} alt="" aria-hidden="true" />
183
- </button>
184
- </div>
76
+ ${component.suggestions.length > 0
77
+ ? html`
78
+ <div class="suggestions-wrapper">
79
+ <p class="suggestions-label">Sugestões de Perguntas</p>
80
+ <div class="suggestions">
81
+ ${component.suggestions.map(
82
+ (suggestion) => html`
83
+ <button
84
+ class="suggestion"
85
+ type="button"
86
+ @click=${() => component.onSuggestionClick(suggestion)}
87
+ >
88
+ ${suggestion}
89
+ </button>
90
+ `,
91
+ )}
92
+ </div>
93
+ </div>
94
+ `
95
+ : null}
96
+
97
+ <form
98
+ @submit=${(event: SubmitEvent) => component.handleSubmit(event)}
99
+ aria-busy=${component.isLoading}
100
+ >
101
+ <input
102
+ type="text"
103
+ placeholder=${component.placeholder}
104
+ .value=${component.message}
105
+ @input=${(event: InputEvent) => {
106
+ component.message = (event.target as HTMLInputElement).value;
107
+ }}
108
+ ?disabled=${component.isLoading}
109
+ />
110
+ <button
111
+ class="input-button submit-button"
112
+ type="submit"
113
+ aria-label="Enviar mensagem"
114
+ ?disabled=${component.isLoading}
115
+ >
116
+ <img src=${arrowButtonUrl} alt="" aria-hidden="true" />
117
+ </button>
118
+ </form>
119
+
120
+ <p class="footnote">
121
+ IA pode cometer erros. Por isso lembre-se de conferir informacoes importantes.
122
+ </p>
123
+ </div>
124
+ </div>
125
+ `;
126
+ };
127
+
128
+ export const renderMiniPanel = (component: RioAssistWidget) => {
129
+ const chatSurface = renderChatSurface(component);
130
+
131
+ return html`
132
+ <aside class=${classMap({ panel: true, open: component.open })} role="dialog">
133
+ <header class="panel-header">
134
+ <div class="panel-header__top">
135
+ <span class="panel-title">${component.titleText}</span>
136
+ <button
137
+ class="close-button"
138
+ @click=${() => component.handleCloseAction()}
139
+ aria-label="Fechar Rio Insight"
140
+ >
141
+ <img src=${closeIconUrl} alt="" aria-hidden="true" />
142
+ </button>
143
+ </div>
185
144
  <div class="panel-header__actions">
186
145
  <button
187
146
  class="conversations-button"
188
147
  type="button"
189
148
  @click=${() => component.toggleConversationsPanel()}
190
- >
191
- <img src=${hamburgerIconUrl} alt="" aria-hidden="true" />
192
- Minhas Conversas
193
- </button>
149
+ >
150
+ <img src=${hamburgerIconUrl} alt="" aria-hidden="true" />
151
+ Minhas Conversas
152
+ </button>
194
153
  <div class="panel-header__icons">
195
- ${component.showConversations
154
+ <button
155
+ type="button"
156
+ class="short-answer-toggle short-answer-toggle--header"
157
+ role="switch"
158
+ aria-checked=${component.shortAnswerEnabled}
159
+ @click=${() => component.toggleShortAnswers()}
160
+ >
161
+ <span
162
+ class=${classMap({
163
+ 'short-answer-toggle__track': true,
164
+ 'short-answer-toggle__track--on': component.shortAnswerEnabled,
165
+ })}
166
+ aria-hidden="true"
167
+ >
168
+ <span class="short-answer-toggle__thumb"></span>
169
+ </span>
170
+ <span class="short-answer-toggle__label">Respostas rápidas</span>
171
+ </button>
172
+
173
+ ${component.hasActiveConversation
196
174
  ? html`
197
175
  <button
198
176
  class="panel-header__icon-button conversations-plus-button"
@@ -215,10 +193,10 @@ export const renderMiniPanel = (component: RioAssistWidget) => {
215
193
  </div>
216
194
  </div>
217
195
  </header>
218
-
219
- ${chatSurface}
220
-
221
- ${renderConversationsPanel(component, { variant: 'drawer' })}
222
- </aside>
223
- `;
224
- };
196
+
197
+ ${chatSurface}
198
+
199
+ ${renderConversationsPanel(component, { variant: 'drawer' })}
200
+ </aside>
201
+ `;
202
+ };
@@ -1,116 +1,125 @@
1
- import { css } from 'lit';
2
- import { floatingButtonStyles } from '../floating-button/floating-button.styles';
3
- import { miniPanelStyles } from '../mini-panel/mini-panel.styles';
4
- import { fullscreenStyles } from '../fullscreen/fullscreen.styles';
5
- import { conversationsPanelStyles } from '../conversations-panel/conversations-panel.styles';
6
-
7
- const baseStyles = css`
8
- @import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@700&display=swap');
9
-
10
- :host {
11
- position: fixed;
12
- inset: 0;
13
- font-family: 'Inter', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
14
- color: #1c2a33;
15
- z-index: 2147483000;
16
- }
17
-
18
- button {
19
- font: inherit;
20
- border: none;
21
- cursor: pointer;
22
- border-radius: 999px;
23
- transition: transform 0.2s ease, box-shadow 0.2s ease;
24
- }
25
-
26
- .dialog-overlay {
27
- position: fixed;
28
- inset: 0;
29
- background: rgba(0, 0, 0, 0.35);
30
- display: grid;
31
- place-items: center;
32
- z-index: 2147484000;
33
- pointer-events: auto;
34
- }
35
-
36
- .dialog {
37
- width: min(360px, calc(100% - 32px));
38
- background: #fff;
39
- border-radius: 12px;
40
- box-shadow: 0 14px 32px rgba(0, 0, 0, 0.22);
41
- padding: 20px;
42
- display: flex;
43
- flex-direction: column;
44
- gap: 16px;
45
- }
46
-
1
+ import { css } from 'lit';
2
+ import { floatingButtonStyles } from '../floating-button/floating-button.styles';
3
+ import { miniPanelStyles } from '../mini-panel/mini-panel.styles';
4
+ import { fullscreenStyles } from '../fullscreen/fullscreen.styles';
5
+ import { conversationsPanelStyles } from '../conversations-panel/conversations-panel.styles';
6
+
7
+ const baseStyles = css`
8
+ @import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@700&display=swap');
9
+
10
+ :host {
11
+ position: fixed;
12
+ inset: 0;
13
+ font-family: 'Inter', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
14
+ color: #1c2a33;
15
+ z-index: 2147483000;
16
+ }
17
+
18
+ button {
19
+ font: inherit;
20
+ border: none;
21
+ cursor: pointer;
22
+ border-radius: 999px;
23
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
24
+ }
25
+
26
+ .dialog-overlay {
27
+ position: fixed;
28
+ inset: 0;
29
+ background: rgba(0, 0, 0, 0.35);
30
+ display: grid;
31
+ place-items: center;
32
+ z-index: 2147484000;
33
+ pointer-events: auto;
34
+ }
35
+
36
+ .dialog {
37
+ width: auto;
38
+ min-width: 360px;
39
+ max-width: calc(100% - 32px);
40
+ box-sizing: border-box;
41
+ background: #fff;
42
+ border-radius: 12px;
43
+ box-shadow: 0 14px 32px rgba(0, 0, 0, 0.22);
44
+ padding: 20px;
45
+ display: flex;
46
+ flex-direction: column;
47
+ gap: 16px;
48
+ }
49
+
47
50
  .dialog__message {
48
51
  margin: 0;
49
52
  font-size: 16px;
50
53
  color: #1f2f36;
54
+ text-align: center;
51
55
  }
52
-
53
- .dialog__message--title {
54
- font-weight: 700;
55
- }
56
-
57
- .dialog__message--error {
58
- color: #d9534f;
59
- white-space: pre-wrap;
60
- }
61
-
62
- .dialog__input {
63
- width: 100%;
64
- box-sizing: border-box;
65
- padding: 10px 12px;
66
- border-radius: 8px;
67
- border: 1px solid #c7d0d9;
68
- font: inherit;
69
- outline: none;
70
- }
71
-
72
- .dialog__input:focus {
73
- border-color: var(--accent-color, #008b9a);
74
- box-shadow: 0 0 0 2px rgba(0, 139, 154, 0.2);
75
- }
76
-
56
+
57
+ .dialog__message--title {
58
+ font-weight: 700;
59
+ text-transform: uppercase;
60
+ }
61
+
62
+ .dialog__message--error {
63
+ color: #d9534f;
64
+ white-space: pre-wrap;
65
+ }
66
+
67
+ .dialog__input {
68
+ width: 100%;
69
+ box-sizing: border-box;
70
+ padding: 10px 12px;
71
+ border-radius: 8px;
72
+ border: 1px solid #c7d0d9;
73
+ font: inherit;
74
+ outline: none;
75
+ }
76
+
77
+ .dialog__input:focus {
78
+ border-color: var(--accent-color, #008b9a);
79
+ box-shadow: 0 0 0 2px rgba(0, 139, 154, 0.2);
80
+ }
81
+
77
82
  .dialog__actions {
78
83
  display: flex;
79
- justify-content: flex-end;
84
+ justify-content: center;
80
85
  gap: 10px;
86
+ flex-wrap: nowrap;
87
+ align-items: center;
81
88
  }
82
-
89
+
83
90
  .dialog__button {
84
- min-width: 96px;
91
+ min-width: max-content;
85
92
  height: 36px;
86
- padding: 0 14px;
93
+ padding: 0 16px;
87
94
  border-radius: 8px;
88
95
  border: 1px solid transparent;
89
96
  font-weight: 600;
97
+ text-transform: uppercase;
98
+ white-space: nowrap;
90
99
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
91
100
  }
92
-
101
+
93
102
  .dialog__button--ghost {
94
103
  background: #fff;
95
104
  border-color: #c7d0d9;
96
105
  color: #1f2f36;
97
106
  }
98
-
99
- .dialog__button--danger {
100
- background: #d9534f;
101
- color: #fff;
102
- }
103
-
107
+
108
+ .dialog__button--danger {
109
+ background: #d9534f;
110
+ color: #fff;
111
+ }
112
+
104
113
  .dialog__button--primary {
105
- background: var(--accent-color, #008b9a);
114
+ background: #008b9a;
106
115
  color: #fff;
107
116
  }
108
- `;
109
-
110
- export const widgetStyles = [
111
- baseStyles,
112
- floatingButtonStyles,
113
- miniPanelStyles,
114
- fullscreenStyles,
115
- conversationsPanelStyles,
116
- ];
117
+ `;
118
+
119
+ export const widgetStyles = [
120
+ baseStyles,
121
+ floatingButtonStyles,
122
+ miniPanelStyles,
123
+ fullscreenStyles,
124
+ conversationsPanelStyles,
125
+ ];