@bbki.ng/bb-msg-history 0.3.0 → 0.5.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/component.d.ts +4 -0
- package/dist/component.js +44 -1
- package/dist/const/authors.js +6 -6
- package/dist/const/styles.js +156 -6
- package/dist/const/theme.js +14 -2
- package/dist/index.dev.js +1 -12
- package/dist/index.js.map +1 -0
- package/dist/src/component.d.ts +39 -0
- package/dist/src/component.js +184 -0
- package/dist/src/const/authors.d.ts +10 -0
- package/dist/src/const/authors.js +29 -0
- package/dist/src/const/styles.d.ts +12 -0
- package/dist/src/const/styles.js +425 -0
- package/dist/src/const/theme.d.ts +6 -0
- package/dist/src/const/theme.js +44 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +12 -0
- package/dist/src/types/index.d.ts +34 -0
- package/dist/src/types/index.js +4 -0
- package/dist/src/utils/author-resolver.d.ts +11 -0
- package/dist/src/utils/author-resolver.js +75 -0
- package/dist/src/utils/avatar.d.ts +4 -0
- package/dist/src/utils/avatar.js +18 -0
- package/dist/src/utils/html.d.ts +12 -0
- package/dist/src/utils/html.js +33 -0
- package/dist/src/utils/message-builder.d.ts +13 -0
- package/dist/src/utils/message-builder.js +60 -0
- package/dist/src/utils/message-parser.d.ts +6 -0
- package/dist/src/utils/message-parser.js +22 -0
- package/dist/src/utils/registration.d.ts +8 -0
- package/dist/src/utils/registration.js +28 -0
- package/dist/src/utils/scroll-button.d.ts +4 -0
- package/dist/src/utils/scroll-button.js +12 -0
- package/dist/src/utils/tooltip.d.ts +5 -0
- package/dist/src/utils/tooltip.js +17 -0
- package/dist/tests/html.test.d.ts +1 -0
- package/dist/tests/html.test.js +35 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/utils/author-resolver.js +7 -3
- package/dist/utils/avatar.js +8 -8
- package/dist/utils/message-builder.js +15 -4
- package/dist/utils/registration.js +3 -4
- package/dist/utils/scroll-button.d.ts +4 -0
- package/dist/utils/scroll-button.js +12 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +8 -0
- package/package.json +32 -7
- package/src/component.ts +67 -13
- package/src/const/authors.ts +6 -6
- package/src/const/styles.ts +156 -6
- package/src/const/theme.ts +14 -2
- package/src/types/index.ts +1 -0
- package/src/utils/author-resolver.ts +8 -4
- package/src/utils/avatar.ts +8 -8
- package/src/utils/message-builder.ts +19 -5
- package/src/utils/message-parser.ts +5 -5
- package/src/utils/registration.ts +5 -5
- package/src/utils/scroll-button.ts +12 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main component styles
|
|
3
|
+
*/
|
|
4
|
+
export declare const MAIN_STYLES: string;
|
|
5
|
+
/**
|
|
6
|
+
* Empty state styles
|
|
7
|
+
*/
|
|
8
|
+
export declare const EMPTY_STYLES: string;
|
|
9
|
+
/**
|
|
10
|
+
* Fallback styles for when custom elements are not supported
|
|
11
|
+
*/
|
|
12
|
+
export declare const FALLBACK_STYLES: string;
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { THEME } from './theme.js';
|
|
2
|
+
/**
|
|
3
|
+
* Main component styles
|
|
4
|
+
*/
|
|
5
|
+
export const MAIN_STYLES = `
|
|
6
|
+
:host {
|
|
7
|
+
display: block;
|
|
8
|
+
position: relative;
|
|
9
|
+
font-family: "PT Sans", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
|
10
|
+
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
|
11
|
+
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
|
12
|
+
"Noto Color Emoji";
|
|
13
|
+
--bb-bg-color: ${THEME.gray[50]};
|
|
14
|
+
--bb-max-height: 600px;
|
|
15
|
+
--bb-avatar-bg: #ffffff;
|
|
16
|
+
--bb-avatar-color: ${THEME.gray[600]};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.history {
|
|
20
|
+
margin: 0 auto;
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
gap: 0.25rem;
|
|
24
|
+
max-height: var(--bb-max-height, 600px);
|
|
25
|
+
overflow-y: auto;
|
|
26
|
+
scroll-behavior: smooth;
|
|
27
|
+
background-color: transparent;
|
|
28
|
+
border-radius: 0.5rem;
|
|
29
|
+
/* Firefox scrollbar */
|
|
30
|
+
scrollbar-width: thin;
|
|
31
|
+
scrollbar-color: ${THEME.gray[400]} transparent;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Custom scrollbar for webkit browsers */
|
|
35
|
+
.history::-webkit-scrollbar {
|
|
36
|
+
width: 6px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.history::-webkit-scrollbar-track {
|
|
40
|
+
background: transparent;
|
|
41
|
+
border-radius: 3px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.history::-webkit-scrollbar-thumb {
|
|
45
|
+
background: ${THEME.gray[400]};
|
|
46
|
+
border-radius: 3px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.history::-webkit-scrollbar-thumb:hover {
|
|
50
|
+
background: ${THEME.gray[500]};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Scroll to bottom button */
|
|
54
|
+
.scroll-to-bottom {
|
|
55
|
+
position: absolute;
|
|
56
|
+
bottom: 16px;
|
|
57
|
+
left: 50%;
|
|
58
|
+
width: 36px;
|
|
59
|
+
height: 36px;
|
|
60
|
+
border-radius: 50%;
|
|
61
|
+
background: transparent;
|
|
62
|
+
border: none;
|
|
63
|
+
color: ${THEME.gray[500]};
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
opacity: 0;
|
|
69
|
+
visibility: hidden;
|
|
70
|
+
transform: translateX(-50%) translateY(10px) scale(0.9);
|
|
71
|
+
transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s ease;
|
|
72
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
|
|
73
|
+
z-index: 10;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.scroll-to-bottom.visible {
|
|
77
|
+
opacity: 1;
|
|
78
|
+
visibility: visible;
|
|
79
|
+
transform: translateX(-50%) translateY(0) scale(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.scroll-to-bottom:hover {
|
|
83
|
+
color: ${THEME.gray[700]};
|
|
84
|
+
transform: translateX(-50%) translateY(-2px);
|
|
85
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.scroll-to-bottom:active {
|
|
89
|
+
transform: translateX(-50%) translateY(0) scale(0.95);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.scroll-to-bottom svg {
|
|
93
|
+
width: 20px;
|
|
94
|
+
height: 20px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Message row layout */
|
|
98
|
+
.msg-row {
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: flex-end;
|
|
101
|
+
gap: 0.5rem;
|
|
102
|
+
max-width: 80%;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.msg-row--left {
|
|
106
|
+
align-self: flex-start;
|
|
107
|
+
margin-right: auto;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.msg-row--right {
|
|
111
|
+
align-self: flex-end;
|
|
112
|
+
margin-left: auto;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.msg-row--subsequent {
|
|
116
|
+
margin-top: 0.125rem;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.msg-row--new-author {
|
|
120
|
+
margin-top: 0.75rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.msg-row--new-author:first-child {
|
|
124
|
+
margin-top: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Avatar container */
|
|
128
|
+
.avatar-wrapper {
|
|
129
|
+
position: relative;
|
|
130
|
+
flex-shrink: 0;
|
|
131
|
+
width: 1.75rem;
|
|
132
|
+
height: 1.75rem;
|
|
133
|
+
background: #ffffff;
|
|
134
|
+
border-radius: 50%;
|
|
135
|
+
overflow: hidden;
|
|
136
|
+
cursor: help;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.avatar-wrapper--hidden {
|
|
140
|
+
opacity: 0;
|
|
141
|
+
pointer-events: none;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.avatar {
|
|
145
|
+
width: 100%;
|
|
146
|
+
height: 100%;
|
|
147
|
+
display: flex;
|
|
148
|
+
align-items: center;
|
|
149
|
+
justify-content: center;
|
|
150
|
+
border-radius: 50%;
|
|
151
|
+
overflow: hidden;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.avatar svg {
|
|
155
|
+
width: 100%;
|
|
156
|
+
height: 100%;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Hover tooltip */
|
|
160
|
+
.avatar-tooltip {
|
|
161
|
+
position: fixed;
|
|
162
|
+
padding: 0.25rem 0.5rem;
|
|
163
|
+
background: ${THEME.gray[800]};
|
|
164
|
+
color: ${THEME.gray[50]};
|
|
165
|
+
font-size: 0.75rem;
|
|
166
|
+
border-radius: 0.25rem;
|
|
167
|
+
white-space: nowrap;
|
|
168
|
+
opacity: 0;
|
|
169
|
+
visibility: hidden;
|
|
170
|
+
pointer-events: none;
|
|
171
|
+
z-index: 10;
|
|
172
|
+
font-weight: 500;
|
|
173
|
+
letter-spacing: 0.02em;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.avatar-tooltip::after {
|
|
177
|
+
content: '';
|
|
178
|
+
position: absolute;
|
|
179
|
+
top: calc(100% - 1px);
|
|
180
|
+
left: 50%;
|
|
181
|
+
transform: translateX(-50%);
|
|
182
|
+
border: 4px solid transparent;
|
|
183
|
+
border-top-color: ${THEME.gray[800]};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.avatar-wrapper:hover .avatar-tooltip {
|
|
187
|
+
opacity: 1;
|
|
188
|
+
visibility: visible;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* Message content area */
|
|
192
|
+
.msg-content {
|
|
193
|
+
display: flex;
|
|
194
|
+
flex-direction: column;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.msg-bubble {
|
|
198
|
+
padding: 0.625rem 0.875rem;
|
|
199
|
+
font-size: 0.9375rem;
|
|
200
|
+
line-height: 1.5;
|
|
201
|
+
word-wrap: break-word;
|
|
202
|
+
overflow-wrap: anywhere;
|
|
203
|
+
word-break: break-word;
|
|
204
|
+
border-radius: 1rem;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* Left bubble */
|
|
208
|
+
.msg-bubble--left {
|
|
209
|
+
border-bottom-left-radius: 0.25rem;
|
|
210
|
+
background-color: ${THEME.gray[200]};
|
|
211
|
+
color: ${THEME.gray[900]};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Right bubble */
|
|
215
|
+
.msg-bubble--right {
|
|
216
|
+
border-bottom-right-radius: 0.25rem;
|
|
217
|
+
color: ${THEME.gray[900]};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Empty state */
|
|
221
|
+
.empty-state {
|
|
222
|
+
text-align: center;
|
|
223
|
+
padding: 2rem;
|
|
224
|
+
color: ${THEME.gray[400]};
|
|
225
|
+
font-size: 0.875rem;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Mobile responsive */
|
|
229
|
+
@media (max-width: 480px) {
|
|
230
|
+
.history {
|
|
231
|
+
max-height: var(--bb-max-height, 70vh);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.msg-row {
|
|
235
|
+
max-width: 85%;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.msg-bubble {
|
|
239
|
+
font-size: 0.9375rem;
|
|
240
|
+
padding: 0.5rem 0.75rem;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.avatar-wrapper {
|
|
244
|
+
width: 1.5rem;
|
|
245
|
+
height: 1.5rem;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.scroll-to-bottom {
|
|
249
|
+
width: 32px;
|
|
250
|
+
height: 32px;
|
|
251
|
+
bottom: 12px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.scroll-to-bottom svg {
|
|
255
|
+
width: 18px;
|
|
256
|
+
height: 18px;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* Dark mode styles - shared between media query and attribute */
|
|
261
|
+
:host([theme="dark"]) {
|
|
262
|
+
--bb-bg-color: ${THEME.gray[900]};
|
|
263
|
+
--bb-avatar-bg: ${THEME.slate[600]};
|
|
264
|
+
--bb-avatar-color: ${THEME.slate[200]};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
:host([theme="dark"]) .history {
|
|
268
|
+
background-color: transparent;
|
|
269
|
+
scrollbar-color: ${THEME.gray[600]} transparent;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
:host([theme="dark"]) .history::-webkit-scrollbar-thumb {
|
|
273
|
+
background: ${THEME.gray[600]};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
:host([theme="dark"]) .history::-webkit-scrollbar-thumb:hover {
|
|
277
|
+
background: ${THEME.gray[500]};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
:host([theme="dark"]) .msg-bubble {
|
|
281
|
+
color: ${THEME.slate[100]};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
:host([theme="dark"]) .msg-bubble--right {
|
|
285
|
+
background-color: ${THEME.slate[700]};
|
|
286
|
+
color: ${THEME.slate[100]};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
:host([theme="dark"]) .msg-bubble--left {
|
|
290
|
+
background-color: ${THEME.slate[800]};
|
|
291
|
+
border: 1px solid ${THEME.slate[700]};
|
|
292
|
+
color: ${THEME.slate[100]};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
:host([theme="dark"]) .avatar-wrapper {
|
|
296
|
+
background: ${THEME.slate[600]};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
:host([theme="dark"]) .empty-state {
|
|
300
|
+
color: ${THEME.gray[500]};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
:host([theme="dark"]) .scroll-to-bottom {
|
|
304
|
+
background: ${THEME.slate[800]};
|
|
305
|
+
border: none;
|
|
306
|
+
color: ${THEME.slate[300]};
|
|
307
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
:host([theme="dark"]) .scroll-to-bottom:hover {
|
|
311
|
+
color: ${THEME.slate[200]};
|
|
312
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* System dark mode preference */
|
|
316
|
+
@media (prefers-color-scheme: dark) {
|
|
317
|
+
:host {
|
|
318
|
+
--bb-bg-color: ${THEME.gray[900]};
|
|
319
|
+
--bb-avatar-bg: ${THEME.slate[600]};
|
|
320
|
+
--bb-avatar-color: ${THEME.slate[200]};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.history {
|
|
324
|
+
background-color: transparent;
|
|
325
|
+
scrollbar-color: ${THEME.gray[600]} transparent;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.history::-webkit-scrollbar-thumb {
|
|
329
|
+
background: ${THEME.gray[600]};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.history::-webkit-scrollbar-thumb:hover {
|
|
333
|
+
background: ${THEME.gray[500]};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.msg-bubble {
|
|
337
|
+
color: ${THEME.slate[100]};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.msg-bubble--right {
|
|
341
|
+
background-color: ${THEME.slate[700]};
|
|
342
|
+
color: ${THEME.slate[100]};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.msg-bubble--left {
|
|
346
|
+
background-color: ${THEME.slate[800]};
|
|
347
|
+
border: 1px solid ${THEME.slate[700]};
|
|
348
|
+
color: ${THEME.slate[100]};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.avatar-wrapper {
|
|
352
|
+
background: ${THEME.slate[600]};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.empty-state {
|
|
356
|
+
color: ${THEME.gray[500]};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.scroll-to-bottom {
|
|
360
|
+
background: ${THEME.slate[800]};
|
|
361
|
+
border: none;
|
|
362
|
+
color: ${THEME.slate[300]};
|
|
363
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.scroll-to-bottom:hover {
|
|
367
|
+
color: ${THEME.slate[200]};
|
|
368
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* Reduced motion */
|
|
373
|
+
@media (prefers-reduced-motion: reduce) {
|
|
374
|
+
.history {
|
|
375
|
+
scroll-behavior: auto;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.scroll-to-bottom {
|
|
379
|
+
transition: opacity 0.15s ease, visibility 0.15s ease;
|
|
380
|
+
transform: translateX(-50%);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.scroll-to-bottom.visible {
|
|
384
|
+
transform: translateX(-50%);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.scroll-to-bottom:hover {
|
|
388
|
+
transform: translateX(-50%);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.scroll-to-bottom:active {
|
|
392
|
+
transform: translateX(-50%);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
`;
|
|
396
|
+
/**
|
|
397
|
+
* Empty state styles
|
|
398
|
+
*/
|
|
399
|
+
export const EMPTY_STYLES = `
|
|
400
|
+
:host { display: block; }
|
|
401
|
+
.empty-state {
|
|
402
|
+
text-align: center;
|
|
403
|
+
padding: 2rem;
|
|
404
|
+
color: ${THEME.gray[400]};
|
|
405
|
+
font-size: 0.875rem;
|
|
406
|
+
font-family: inherit;
|
|
407
|
+
}
|
|
408
|
+
`;
|
|
409
|
+
/**
|
|
410
|
+
* Fallback styles for when custom elements are not supported
|
|
411
|
+
*/
|
|
412
|
+
export const FALLBACK_STYLES = `
|
|
413
|
+
background: ${THEME.gray[100]};
|
|
414
|
+
padding: 1rem;
|
|
415
|
+
border-radius: 0.5rem;
|
|
416
|
+
overflow-x: auto;
|
|
417
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
418
|
+
font-size: 0.875rem;
|
|
419
|
+
line-height: 1.5;
|
|
420
|
+
color: ${THEME.gray[900]};
|
|
421
|
+
margin: 0;
|
|
422
|
+
white-space: pre-wrap;
|
|
423
|
+
word-wrap: break-word;
|
|
424
|
+
border: 1px solid ${THEME.gray[200]};
|
|
425
|
+
`;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme color palette
|
|
3
|
+
* Based on Tailwind-like gray scale and custom pink colors
|
|
4
|
+
*/
|
|
5
|
+
export const THEME = {
|
|
6
|
+
gray: {
|
|
7
|
+
50: '#f9fafb',
|
|
8
|
+
100: '#f3f4f6',
|
|
9
|
+
200: '#f5f5f5',
|
|
10
|
+
300: '#d1d5db',
|
|
11
|
+
400: '#9ca3af',
|
|
12
|
+
500: '#6b7280',
|
|
13
|
+
600: '#4b5563',
|
|
14
|
+
700: '#374151',
|
|
15
|
+
800: '#1f2937',
|
|
16
|
+
900: '#111827',
|
|
17
|
+
},
|
|
18
|
+
slate: {
|
|
19
|
+
50: '#f8fafc',
|
|
20
|
+
100: '#f1f5f9',
|
|
21
|
+
200: '#e2e8f0',
|
|
22
|
+
300: '#cbd5e1',
|
|
23
|
+
400: '#94a3b8',
|
|
24
|
+
500: '#64748b',
|
|
25
|
+
600: '#475569',
|
|
26
|
+
700: '#334155',
|
|
27
|
+
800: '#1e293b',
|
|
28
|
+
900: '#0f172a',
|
|
29
|
+
},
|
|
30
|
+
red: {
|
|
31
|
+
50: '#fef2f2',
|
|
32
|
+
100: '#fee2e2',
|
|
33
|
+
200: '#fecaca',
|
|
34
|
+
300: '#fca5a5',
|
|
35
|
+
400: '#f87171',
|
|
36
|
+
500: '#ef4444',
|
|
37
|
+
600: '#dc2626',
|
|
38
|
+
},
|
|
39
|
+
yyPink: {
|
|
40
|
+
50: '#fdf4f4',
|
|
41
|
+
100: '#fbd1d2',
|
|
42
|
+
150: '#f8babc',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BBMsgHistory } from './component.js';
|
|
2
|
+
export { BBMsgHistory };
|
|
3
|
+
export { define } from './utils/registration.js';
|
|
4
|
+
export type { AuthorOptions, AuthorConfig, Message } from './types/index.js';
|
|
5
|
+
declare global {
|
|
6
|
+
interface HTMLElementTagNameMap {
|
|
7
|
+
'bb-msg-history': BBMsgHistory;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BBMsgHistory } from './component.js';
|
|
2
|
+
import { initBBMsgHistory } from './utils/registration.js';
|
|
3
|
+
// Auto-initialize
|
|
4
|
+
if (document.readyState === 'loading') {
|
|
5
|
+
document.addEventListener('DOMContentLoaded', () => initBBMsgHistory(BBMsgHistory));
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
initBBMsgHistory(BBMsgHistory);
|
|
9
|
+
}
|
|
10
|
+
// Re-exports
|
|
11
|
+
export { BBMsgHistory };
|
|
12
|
+
export { define } from './utils/registration.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for bb-msg-history
|
|
3
|
+
*/
|
|
4
|
+
/** Single message structure */
|
|
5
|
+
export interface Message {
|
|
6
|
+
author: string;
|
|
7
|
+
text: string;
|
|
8
|
+
}
|
|
9
|
+
/** Internal author configuration with resolved values */
|
|
10
|
+
export interface AuthorConfig {
|
|
11
|
+
avatar: string;
|
|
12
|
+
bubbleColor: string;
|
|
13
|
+
textColor: string;
|
|
14
|
+
side: 'left' | 'right';
|
|
15
|
+
isCustomAvatar: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** User-facing options for configuring an author */
|
|
18
|
+
export interface AuthorOptions {
|
|
19
|
+
/** Avatar HTML string: SVG, <img>, emoji, or plain text */
|
|
20
|
+
avatar?: string;
|
|
21
|
+
/** Which side the messages appear on */
|
|
22
|
+
side?: 'left' | 'right';
|
|
23
|
+
/** Bubble background color */
|
|
24
|
+
bubbleColor?: string;
|
|
25
|
+
/** Text color inside bubble */
|
|
26
|
+
textColor?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Theme color palette */
|
|
29
|
+
export interface Theme {
|
|
30
|
+
gray: Record<string, string>;
|
|
31
|
+
slate: Record<string, string>;
|
|
32
|
+
red: Record<string, string>;
|
|
33
|
+
yyPink: Record<string, string>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AuthorConfig, AuthorOptions } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve author configuration with the following priority:
|
|
4
|
+
* 1. User config (exact match)
|
|
5
|
+
* 2. User config (fuzzy match - author name contains configured key)
|
|
6
|
+
* 3. Built-in first-char avatar authors
|
|
7
|
+
* 4. Built-in exact match
|
|
8
|
+
* 5. Built-in fuzzy match
|
|
9
|
+
* 6. Default: letter avatar, left side
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveAuthorConfig(author: string, userAuthors: Map<string, AuthorOptions>): AuthorConfig;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { THEME } from '../const/theme.js';
|
|
2
|
+
import { AUTHOR_CONFIG, FIRST_CHAR_AVATAR_AUTHORS } from '../const/authors.js';
|
|
3
|
+
import { wrapAvatarHtml } from './html.js';
|
|
4
|
+
import { generateLetterAvatar } from './avatar.js';
|
|
5
|
+
/**
|
|
6
|
+
* Resolve author configuration with the following priority:
|
|
7
|
+
* 1. User config (exact match)
|
|
8
|
+
* 2. User config (fuzzy match - author name contains configured key)
|
|
9
|
+
* 3. Built-in first-char avatar authors
|
|
10
|
+
* 4. Built-in exact match
|
|
11
|
+
* 5. Built-in fuzzy match
|
|
12
|
+
* 6. Default: letter avatar, left side
|
|
13
|
+
*/
|
|
14
|
+
export function resolveAuthorConfig(author, userAuthors) {
|
|
15
|
+
// 1. User custom config (exact match)
|
|
16
|
+
const userConfig = userAuthors.get(author);
|
|
17
|
+
if (userConfig) {
|
|
18
|
+
return {
|
|
19
|
+
avatar: userConfig.avatar
|
|
20
|
+
? wrapAvatarHtml(userConfig.avatar)
|
|
21
|
+
: generateLetterAvatar(author.charAt(0).toUpperCase()),
|
|
22
|
+
bubbleColor: userConfig.bubbleColor || THEME.gray[50],
|
|
23
|
+
textColor: userConfig.textColor || THEME.gray[900],
|
|
24
|
+
side: userConfig.side || 'left',
|
|
25
|
+
isCustomAvatar: !!userConfig.avatar,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// 2. User custom config (fuzzy match)
|
|
29
|
+
for (const [key, cfg] of userAuthors.entries()) {
|
|
30
|
+
if (author.includes(key)) {
|
|
31
|
+
return {
|
|
32
|
+
avatar: cfg.avatar
|
|
33
|
+
? wrapAvatarHtml(cfg.avatar)
|
|
34
|
+
: generateLetterAvatar(author.charAt(0).toUpperCase()),
|
|
35
|
+
bubbleColor: cfg.bubbleColor || THEME.gray[50],
|
|
36
|
+
textColor: cfg.textColor || THEME.gray[900],
|
|
37
|
+
side: cfg.side || 'left',
|
|
38
|
+
isCustomAvatar: !!cfg.avatar,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 3. Built-in first-char avatar authors
|
|
43
|
+
if (FIRST_CHAR_AVATAR_AUTHORS.has(author)) {
|
|
44
|
+
const config = AUTHOR_CONFIG[author];
|
|
45
|
+
const firstChar = author.charAt(0);
|
|
46
|
+
return {
|
|
47
|
+
...(config || {
|
|
48
|
+
bubbleColor: THEME.gray[50],
|
|
49
|
+
textColor: THEME.gray[900],
|
|
50
|
+
side: 'left',
|
|
51
|
+
}),
|
|
52
|
+
avatar: generateLetterAvatar(firstChar),
|
|
53
|
+
isCustomAvatar: false,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// 4. Built-in exact match
|
|
57
|
+
if (AUTHOR_CONFIG[author]) {
|
|
58
|
+
return { ...AUTHOR_CONFIG[author], isCustomAvatar: true };
|
|
59
|
+
}
|
|
60
|
+
// 5. Built-in fuzzy match
|
|
61
|
+
for (const [key, config] of Object.entries(AUTHOR_CONFIG)) {
|
|
62
|
+
if (author.includes(key)) {
|
|
63
|
+
return { ...config, isCustomAvatar: true };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// 6. Default: letter avatar, left side
|
|
67
|
+
const firstChar = author.charAt(0).toUpperCase();
|
|
68
|
+
return {
|
|
69
|
+
avatar: generateLetterAvatar(firstChar),
|
|
70
|
+
bubbleColor: THEME.gray[50],
|
|
71
|
+
textColor: THEME.gray[900],
|
|
72
|
+
side: 'left',
|
|
73
|
+
isCustomAvatar: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { THEME } from '../const/theme.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a letter avatar with the given letter
|
|
4
|
+
*/
|
|
5
|
+
export function generateLetterAvatar(letter) {
|
|
6
|
+
return `<div style="
|
|
7
|
+
width: 100%;
|
|
8
|
+
height: 100%;
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
background: var(--bb-avatar-bg, #ffffff);
|
|
13
|
+
color: var(--bb-avatar-color, ${THEME.gray[600]});
|
|
14
|
+
font-size: 14px;
|
|
15
|
+
font-weight: 600;
|
|
16
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
|
|
17
|
+
">${letter}</div>`;
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML utility functions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Escape HTML special characters to prevent XSS
|
|
6
|
+
*/
|
|
7
|
+
export declare function escapeHtml(str: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Wrap plain text/emoji avatar in a styled container
|
|
10
|
+
* If HTML tags are present, return as-is
|
|
11
|
+
*/
|
|
12
|
+
export declare function wrapAvatarHtml(html: string): string;
|