@dssp/project 1.0.0-alpha.8 → 1.0.0-y.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 (102) hide show
  1. package/dist-client/index.d.ts +1 -0
  2. package/dist-client/index.js +1 -1
  3. package/dist-client/index.js.map +1 -1
  4. package/dist-client/pages/lib/chatbot-widget.d.ts +53 -0
  5. package/dist-client/pages/lib/chatbot-widget.js +631 -0
  6. package/dist-client/pages/lib/chatbot-widget.js.map +1 -0
  7. package/dist-client/pages/lib/select2-component.d.ts +1 -1
  8. package/dist-client/pages/lib/select2-component.js +35 -35
  9. package/dist-client/pages/lib/select2-component.js.map +1 -1
  10. package/dist-client/pages/project/component/pagenation.d.ts +18 -0
  11. package/dist-client/pages/project/component/pagenation.js +142 -0
  12. package/dist-client/pages/project/component/pagenation.js.map +1 -0
  13. package/dist-client/pages/project/component/project-update-header.js +26 -3
  14. package/dist-client/pages/project/component/project-update-header.js.map +1 -1
  15. package/dist-client/pages/project/popup/checklist/task-checklist-attachment-list-popup.d.ts +1 -0
  16. package/dist-client/pages/project/popup/checklist/task-checklist-attachment-list-popup.js +309 -0
  17. package/dist-client/pages/project/popup/checklist/task-checklist-attachment-list-popup.js.map +1 -0
  18. package/dist-client/pages/project/popup/checklist/task-checklist-comment-list-popup.d.ts +1 -0
  19. package/dist-client/pages/project/popup/checklist/task-checklist-comment-list-popup.js +357 -0
  20. package/dist-client/pages/project/popup/checklist/task-checklist-comment-list-popup.js.map +1 -0
  21. package/dist-client/pages/project/popup/checklist/task-checklist-create-popup.d.ts +1 -0
  22. package/dist-client/pages/project/popup/checklist/task-checklist-create-popup.js +681 -0
  23. package/dist-client/pages/project/popup/checklist/task-checklist-create-popup.js.map +1 -0
  24. package/dist-client/pages/project/popup/checklist/task-checklist-view.d.ts +32 -0
  25. package/dist-client/pages/project/popup/checklist/task-checklist-view.js +621 -0
  26. package/dist-client/pages/project/popup/checklist/task-checklist-view.js.map +1 -0
  27. package/dist-client/pages/project/popup/popup-plan-export.js +8 -2
  28. package/dist-client/pages/project/popup/popup-plan-export.js.map +1 -1
  29. package/dist-client/pages/project/popup/{popup-schedule-upload.d.ts → popup-task-upload.d.ts} +1 -1
  30. package/dist-client/pages/project/popup/{popup-schedule-upload.js → popup-task-upload.js} +9 -9
  31. package/dist-client/pages/project/popup/popup-task-upload.js.map +1 -0
  32. package/dist-client/pages/project/project-completed-list.d.ts +5 -0
  33. package/dist-client/pages/project/project-completed-list.js +32 -3
  34. package/dist-client/pages/project/project-completed-list.js.map +1 -1
  35. package/dist-client/pages/project/project-detail.js +50 -20
  36. package/dist-client/pages/project/project-detail.js.map +1 -1
  37. package/dist-client/pages/project/project-list.d.ts +41 -0
  38. package/dist-client/pages/project/project-list.js +66 -3
  39. package/dist-client/pages/project/project-list.js.map +1 -1
  40. package/dist-client/pages/project/project-setting-list.d.ts +5 -0
  41. package/dist-client/pages/project/project-setting-list.js +32 -3
  42. package/dist-client/pages/project/project-setting-list.js.map +1 -1
  43. package/dist-client/pages/project/{project-schedule-list.d.ts → project-task-list.d.ts} +2 -2
  44. package/dist-client/pages/project/{project-schedule-list.js → project-task-list.js} +11 -11
  45. package/dist-client/pages/project/project-task-list.js.map +1 -0
  46. package/dist-client/pages/project/{project-schedule.d.ts → project-task.d.ts} +17 -4
  47. package/dist-client/pages/project/project-task.js +686 -0
  48. package/dist-client/pages/project/project-task.js.map +1 -0
  49. package/dist-client/pages/project/project-update.js +221 -28
  50. package/dist-client/pages/project/project-update.js.map +1 -1
  51. package/dist-client/route.d.ts +1 -1
  52. package/dist-client/route.js +4 -4
  53. package/dist-client/route.js.map +1 -1
  54. package/dist-client/tsconfig.tsbuildinfo +1 -1
  55. package/dist-server/controllers/parse-excel.js.map +1 -1
  56. package/dist-server/service/index.d.ts +2 -2
  57. package/dist-server/service/index.js +5 -2
  58. package/dist-server/service/index.js.map +1 -1
  59. package/dist-server/service/project/project-mutation.js +5 -1
  60. package/dist-server/service/project/project-mutation.js.map +1 -1
  61. package/dist-server/service/project/project-query.d.ts +3 -0
  62. package/dist-server/service/project/project-query.js +48 -0
  63. package/dist-server/service/project/project-query.js.map +1 -1
  64. package/dist-server/service/project/project-type.d.ts +5 -0
  65. package/dist-server/service/project/project-type.js +19 -1
  66. package/dist-server/service/project/project-type.js.map +1 -1
  67. package/dist-server/service/project/project.d.ts +9 -0
  68. package/dist-server/service/project/project.js +31 -1
  69. package/dist-server/service/project/project.js.map +1 -1
  70. package/dist-server/service/task/task-query.d.ts +2 -0
  71. package/dist-server/service/task/task-query.js +11 -0
  72. package/dist-server/service/task/task-query.js.map +1 -1
  73. package/dist-server/service/task/task.d.ts +2 -0
  74. package/dist-server/service/task/task.js +6 -0
  75. package/dist-server/service/task/task.js.map +1 -1
  76. package/dist-server/service/task-checklist-binding/index.d.ts +5 -0
  77. package/dist-server/service/task-checklist-binding/index.js +9 -0
  78. package/dist-server/service/task-checklist-binding/index.js.map +1 -0
  79. package/dist-server/service/task-checklist-binding/task-checklist-binding-mutation.d.ts +5 -0
  80. package/dist-server/service/task-checklist-binding/task-checklist-binding-mutation.js +186 -0
  81. package/dist-server/service/task-checklist-binding/task-checklist-binding-mutation.js.map +1 -0
  82. package/dist-server/service/task-checklist-binding/task-checklist-binding-query.d.ts +8 -0
  83. package/dist-server/service/task-checklist-binding/task-checklist-binding-query.js +61 -0
  84. package/dist-server/service/task-checklist-binding/task-checklist-binding-query.js.map +1 -0
  85. package/dist-server/service/task-checklist-binding/task-checklist-binding-type.d.ts +15 -0
  86. package/dist-server/service/task-checklist-binding/task-checklist-binding-type.js +57 -0
  87. package/dist-server/service/task-checklist-binding/task-checklist-binding-type.js.map +1 -0
  88. package/dist-server/service/task-checklist-binding/task-checklist-binding.d.ts +22 -0
  89. package/dist-server/service/task-checklist-binding/task-checklist-binding.js +106 -0
  90. package/dist-server/service/task-checklist-binding/task-checklist-binding.js.map +1 -0
  91. package/dist-server/tsconfig.tsbuildinfo +1 -1
  92. package/package.json +5 -3
  93. package/things-factory.config.js +3 -3
  94. package/translations/en.json +10 -9
  95. package/translations/ja.json +15 -1
  96. package/translations/ko.json +3 -0
  97. package/translations/ms.json +15 -1
  98. package/translations/zh.json +15 -1
  99. package/dist-client/pages/project/popup/popup-schedule-upload.js.map +0 -1
  100. package/dist-client/pages/project/project-schedule-list.js.map +0 -1
  101. package/dist-client/pages/project/project-schedule.js +0 -407
  102. package/dist-client/pages/project/project-schedule.js.map +0 -1
@@ -0,0 +1 @@
1
+ export * from './pages/lib/chatbot-widget';
@@ -1,2 +1,2 @@
1
- "use strict";
1
+ export * from './pages/lib/chatbot-widget';
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"","sourcesContent":[""]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA","sourcesContent":["export * from './pages/lib/chatbot-widget'\n"]}
@@ -0,0 +1,53 @@
1
+ import { LitElement } from 'lit';
2
+ interface SourceItem {
3
+ title: string;
4
+ url: string;
5
+ }
6
+ interface ChatMessage {
7
+ id: string;
8
+ text: string;
9
+ isUser: boolean;
10
+ timestamp: Date;
11
+ sources?: SourceItem[];
12
+ }
13
+ export declare class ChatbotWidget extends LitElement {
14
+ static styles: import("lit").CSSResult;
15
+ static get properties(): {
16
+ isOpen: {
17
+ type: BooleanConstructor;
18
+ };
19
+ messages: {
20
+ type: ArrayConstructor;
21
+ };
22
+ inputValue: {
23
+ type: StringConstructor;
24
+ };
25
+ isLoading: {
26
+ type: BooleanConstructor;
27
+ };
28
+ isSourcesOpen: {
29
+ type: BooleanConstructor;
30
+ };
31
+ currentSources: {
32
+ type: ArrayConstructor;
33
+ };
34
+ };
35
+ isOpen: boolean;
36
+ messages: ChatMessage[];
37
+ inputValue: string;
38
+ isLoading: boolean;
39
+ isSourcesOpen: boolean;
40
+ currentSources: SourceItem[];
41
+ render(): import("lit-html").TemplateResult<1>;
42
+ private boundHandleEscapeKey;
43
+ connectedCallback(): void;
44
+ disconnectedCallback(): void;
45
+ handleEscapeKey(event: KeyboardEvent): void;
46
+ toggleChat(): void;
47
+ scrollToBottom(): void;
48
+ sendMessage(): Promise<void>;
49
+ openSourcesOverlay(sources: SourceItem[]): void;
50
+ closeSourcesOverlay(): void;
51
+ handleKeyPress(event: KeyboardEvent): void;
52
+ }
53
+ export {};
@@ -0,0 +1,631 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ // API 상수
3
+ const CHATBOT_API_URL = 'https://korea-uni-chat-ui.ettisoft.com/chat';
4
+ export class ChatbotWidget extends LitElement {
5
+ constructor() {
6
+ super(...arguments);
7
+ this.isOpen = false;
8
+ this.messages = [];
9
+ this.inputValue = '';
10
+ this.isLoading = false;
11
+ this.isSourcesOpen = false;
12
+ this.currentSources = [];
13
+ this.boundHandleEscapeKey = this.handleEscapeKey.bind(this);
14
+ }
15
+ static get properties() {
16
+ return {
17
+ isOpen: { type: Boolean },
18
+ messages: { type: Array },
19
+ inputValue: { type: String },
20
+ isLoading: { type: Boolean },
21
+ isSourcesOpen: { type: Boolean },
22
+ currentSources: { type: Array }
23
+ };
24
+ }
25
+ render() {
26
+ return html `
27
+ <div class="chatbot-container">
28
+ <!-- 챗봇 아이콘 -->
29
+ <button class="chatbot-icon" @click="${this.toggleChat}">
30
+ <svg viewBox="0 0 24 24">
31
+ <path
32
+ d="M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4l4 4 4-4h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"
33
+ />
34
+ </svg>
35
+ </button>
36
+
37
+ <!-- 대화창 -->
38
+ <div class="chat-window ${this.isOpen ? 'open' : ''}">
39
+ <!-- 헤더 -->
40
+ <div class="chat-header">
41
+ <h3>챗봇 도우미</h3>
42
+ <button class="close-btn" @click="${this.toggleChat}">×</button>
43
+ </div>
44
+
45
+ <!-- 메시지 영역 -->
46
+ <div class="messages-container">
47
+ ${this.messages.length === 0
48
+ ? html `
49
+ <div class="message bot">
50
+ <div class="message-avatar">🤖</div>
51
+ <div class="message-bubble">안녕하세요! 무엇을 도와드릴까요?</div>
52
+ </div>
53
+ `
54
+ : ''}
55
+ ${this.messages.map(message => html `
56
+ <div class="message ${message.isUser ? 'user' : 'bot'}">
57
+ <div class="message-avatar">${message.isUser ? '👤' : '🤖'}</div>
58
+ <div class="message-bubble">
59
+ ${message.text}
60
+ ${!message.isUser && message.sources && message.sources.length
61
+ ? html `
62
+ <div>
63
+ <button class="evidence-btn" @click="${() => this.openSourcesOverlay(message.sources || [])}">
64
+ 근거 ${message.sources.length}개 보기
65
+ </button>
66
+ </div>
67
+ `
68
+ : ''}
69
+ </div>
70
+ </div>
71
+ `)}
72
+ ${this.isLoading
73
+ ? html `
74
+ <div class="message bot">
75
+ <div class="message-avatar">🤖</div>
76
+ <div class="message-bubble">
77
+ <div class="loading-indicator">
78
+ <span>답변 중</span>
79
+ <div class="loading-dots">
80
+ <div class="loading-dot"></div>
81
+ <div class="loading-dot"></div>
82
+ <div class="loading-dot"></div>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ `
88
+ : ''}
89
+ </div>
90
+
91
+ <!-- 입력 영역 -->
92
+ <div class="input-container">
93
+ <input
94
+ class="message-input"
95
+ type="text"
96
+ placeholder="메시지를 입력하세요..."
97
+ .value="${this.inputValue}"
98
+ @input="${(e) => (this.inputValue = e.target.value)}"
99
+ @keypress="${this.handleKeyPress}"
100
+ ?disabled="${this.isLoading}"
101
+ />
102
+ <button class="send-btn" @click="${this.sendMessage}" ?disabled="${this.isLoading || !this.inputValue.trim()}">
103
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
104
+ <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
105
+ </svg>
106
+ </button>
107
+ </div>
108
+ </div>
109
+ <!-- 근거 오버레이 -->
110
+ <div class="overlay ${this.isSourcesOpen ? 'open' : ''}" @click="${this.closeSourcesOverlay}">
111
+ <div class="overlay-panel" @click="${(e) => e.stopPropagation()}">
112
+ <div class="overlay-header">
113
+ <div class="overlay-title">근거 ${this.currentSources.length}개</div>
114
+ <button class="overlay-close" @click="${this.closeSourcesOverlay}">×</button>
115
+ </div>
116
+ <div class="overlay-body">
117
+ <ul class="source-list">
118
+ ${this.currentSources.map((s, idx) => html ` <li class="source-item">
119
+ <a class="source-link" href="${s.url}" target="_blank" rel="noopener noreferrer"
120
+ >[#${idx + 1}] ${s.title}</a
121
+ >
122
+ </li>`)}
123
+ </ul>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ `;
129
+ }
130
+ connectedCallback() {
131
+ super.connectedCallback();
132
+ }
133
+ disconnectedCallback() {
134
+ super.disconnectedCallback();
135
+ // 컴포넌트가 제거될 때 이벤트 리스너 정리
136
+ document.removeEventListener('keydown', this.boundHandleEscapeKey);
137
+ }
138
+ handleEscapeKey(event) {
139
+ if (event.key === 'Escape') {
140
+ if (this.isSourcesOpen) {
141
+ this.isSourcesOpen = false;
142
+ }
143
+ else if (this.isOpen) {
144
+ this.isOpen = false;
145
+ }
146
+ }
147
+ }
148
+ toggleChat() {
149
+ this.isOpen = !this.isOpen;
150
+ if (this.isOpen) {
151
+ // 챗봇이 열릴 때 ESC 키 이벤트 리스너 추가
152
+ document.addEventListener('keydown', this.boundHandleEscapeKey);
153
+ // 챗봇이 열릴 때 스크롤을 맨 아래로
154
+ this.requestUpdate();
155
+ setTimeout(() => this.scrollToBottom(), 100);
156
+ }
157
+ else {
158
+ // 챗봇이 닫힐 때 ESC 키 이벤트 리스너 제거
159
+ document.removeEventListener('keydown', this.boundHandleEscapeKey);
160
+ this.isSourcesOpen = false;
161
+ this.currentSources = [];
162
+ }
163
+ }
164
+ scrollToBottom() {
165
+ var _a;
166
+ const messagesContainer = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.messages-container');
167
+ if (messagesContainer) {
168
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
169
+ }
170
+ }
171
+ async sendMessage() {
172
+ var _a, _b;
173
+ if (!this.inputValue.trim() || this.isLoading)
174
+ return;
175
+ const userMessage = {
176
+ id: Date.now().toString(),
177
+ text: this.inputValue.trim(),
178
+ isUser: true,
179
+ timestamp: new Date()
180
+ };
181
+ this.messages = [...this.messages, userMessage];
182
+ const messageText = this.inputValue.trim();
183
+ this.inputValue = '';
184
+ this.isLoading = true;
185
+ // 사용자 메시지 추가 후 스크롤을 맨 아래로
186
+ setTimeout(() => this.scrollToBottom(), 50);
187
+ // 포커스 유지를 위해 input 요소 참조 저장
188
+ const input = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.message-input');
189
+ try {
190
+ // API 호출
191
+ const response = await fetch(CHATBOT_API_URL, {
192
+ method: 'POST',
193
+ headers: {
194
+ 'Content-Type': 'application/json'
195
+ },
196
+ body: JSON.stringify({ query: messageText, top_k: 6 })
197
+ });
198
+ if (!response.ok) {
199
+ throw new Error(`HTTP ${response.status}`);
200
+ }
201
+ const data = await response.json();
202
+ const botMessage = {
203
+ id: (Date.now() + 1).toString(),
204
+ text: ((_b = data === null || data === void 0 ? void 0 : data.answer) === null || _b === void 0 ? void 0 : _b.trim()) || '죄송합니다. 응답을 처리할 수 없습니다.',
205
+ isUser: false,
206
+ timestamp: new Date(),
207
+ sources: (data === null || data === void 0 ? void 0 : data.sources) || []
208
+ };
209
+ this.messages = [...this.messages, botMessage];
210
+ // 봇 메시지 추가 후 스크롤을 맨 아래로
211
+ setTimeout(() => this.scrollToBottom(), 50);
212
+ }
213
+ catch (error) {
214
+ const errorMessage = {
215
+ id: (Date.now() + 1).toString(),
216
+ text: '죄송합니다. 일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요.',
217
+ isUser: false,
218
+ timestamp: new Date()
219
+ };
220
+ this.messages = [...this.messages, errorMessage];
221
+ // 에러 메시지 추가 후 스크롤을 맨 아래로
222
+ setTimeout(() => this.scrollToBottom(), 50);
223
+ }
224
+ finally {
225
+ this.isLoading = false;
226
+ // 로딩 완료 후 포커스 복원
227
+ setTimeout(() => {
228
+ if (input) {
229
+ input.focus();
230
+ }
231
+ }, 100);
232
+ }
233
+ }
234
+ openSourcesOverlay(sources) {
235
+ if (!sources || sources.length === 0)
236
+ return;
237
+ this.currentSources = sources;
238
+ this.isSourcesOpen = true;
239
+ }
240
+ closeSourcesOverlay() {
241
+ this.isSourcesOpen = false;
242
+ this.currentSources = [];
243
+ }
244
+ handleKeyPress(event) {
245
+ if (event.key === 'Enter' && !event.shiftKey) {
246
+ event.preventDefault();
247
+ this.sendMessage();
248
+ }
249
+ }
250
+ }
251
+ ChatbotWidget.styles = css `
252
+ :host {
253
+ position: fixed;
254
+ bottom: 40px;
255
+ right: 20px;
256
+ z-index: 1000;
257
+ }
258
+
259
+ .chatbot-container {
260
+ position: relative;
261
+ }
262
+
263
+ .chatbot-icon {
264
+ width: 60px;
265
+ height: 60px;
266
+ background: linear-gradient(135deg, var(--md-sys-color-tertiary, #b85d5a) 0%, var(--md-sys-color-primary) 100%);
267
+ border-radius: 50%;
268
+ display: flex;
269
+ align-items: center;
270
+ justify-content: center;
271
+ cursor: pointer;
272
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
273
+ transition: all 0.3s ease;
274
+ border: none;
275
+ outline: none;
276
+ }
277
+
278
+ .chatbot-icon:hover {
279
+ transform: scale(1.1);
280
+ box-shadow: 0 6px 25px rgba(0, 0, 0, 0.2);
281
+ }
282
+
283
+ .chatbot-icon svg {
284
+ width: 28px;
285
+ height: 28px;
286
+ fill: white;
287
+ }
288
+
289
+ .chat-window {
290
+ position: absolute;
291
+ bottom: 80px;
292
+ right: 0;
293
+ width: 350px;
294
+ height: 500px;
295
+ background: white;
296
+ border-radius: 20px;
297
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
298
+ display: flex;
299
+ flex-direction: column;
300
+ overflow: hidden;
301
+ transform: translateY(20px) scale(0.95);
302
+ opacity: 0;
303
+ transition: all 0.3s ease;
304
+ border: 1px solid #e1e5e9;
305
+ pointer-events: none; /* 닫혀있을 때 클릭 차단 해제 */
306
+ }
307
+
308
+ .chat-window.open {
309
+ transform: translateY(0) scale(1);
310
+ opacity: 1;
311
+ pointer-events: auto; /* 열렸을 때 클릭 가능 */
312
+ }
313
+
314
+ .chat-header {
315
+ background: linear-gradient(135deg, var(--md-sys-color-tertiary, #b85d5a) 0%, var(--md-sys-color-primary) 100%);
316
+ color: white;
317
+ padding: 15px 20px;
318
+ display: flex;
319
+ align-items: center;
320
+ justify-content: space-between;
321
+ }
322
+
323
+ .chat-header h3 {
324
+ margin: 0;
325
+ font-size: 18px;
326
+ font-weight: 600;
327
+ }
328
+
329
+ .close-btn {
330
+ background: none;
331
+ border: none;
332
+ color: white;
333
+ cursor: pointer;
334
+ font-size: 32px;
335
+ padding: 0;
336
+ width: 36px;
337
+ height: 36px;
338
+ display: flex;
339
+ align-items: center;
340
+ justify-content: center;
341
+ border-radius: 50%;
342
+ transition: background-color 0.2s ease;
343
+ }
344
+
345
+ .close-btn:hover {
346
+ background-color: rgba(255, 255, 255, 0.2);
347
+ }
348
+
349
+ .messages-container {
350
+ flex: 1;
351
+ overflow-y: auto;
352
+ padding: 20px;
353
+ display: flex;
354
+ flex-direction: column;
355
+ gap: 15px;
356
+ }
357
+
358
+ .message {
359
+ display: flex;
360
+ align-items: flex-end;
361
+ gap: 10px;
362
+ max-width: 80%;
363
+ }
364
+
365
+ .message.user {
366
+ align-self: flex-end;
367
+ flex-direction: row-reverse;
368
+ }
369
+
370
+ .message.bot {
371
+ align-self: flex-start;
372
+ }
373
+
374
+ .message-bubble {
375
+ padding: 12px 16px;
376
+ border-radius: 18px;
377
+ font-size: 14px;
378
+ line-height: 1.4;
379
+ word-wrap: break-word;
380
+ position: relative;
381
+ }
382
+
383
+ .message.user .message-bubble {
384
+ background: linear-gradient(135deg, var(--md-sys-color-tertiary, #b85d5a) 0%, var(--md-sys-color-primary) 100%);
385
+ color: white;
386
+ border-bottom-right-radius: 4px;
387
+ }
388
+
389
+ .message.bot .message-bubble {
390
+ background: #f1f3f4;
391
+ color: #333;
392
+ border-bottom-left-radius: 4px;
393
+ }
394
+
395
+ .message-avatar {
396
+ width: 32px;
397
+ height: 32px;
398
+ border-radius: 50%;
399
+ display: flex;
400
+ align-items: center;
401
+ justify-content: center;
402
+ font-size: 12px;
403
+ font-weight: 600;
404
+ flex-shrink: 0;
405
+ }
406
+
407
+ .message.user .message-avatar {
408
+ background: linear-gradient(135deg, var(--md-sys-color-tertiary, #b85d5a) 0%, var(--md-sys-color-primary) 100%);
409
+ color: white;
410
+ }
411
+
412
+ .message.bot .message-avatar {
413
+ background: #e8eaf0;
414
+ color: #666;
415
+ }
416
+
417
+ .input-container {
418
+ padding: 20px;
419
+ border-top: 1px solid #e1e5e9;
420
+ display: flex;
421
+ gap: 10px;
422
+ align-items: center;
423
+ }
424
+
425
+ .message-input {
426
+ flex: 1;
427
+ border: 1px solid #e1e5e9;
428
+ border-radius: 25px;
429
+ padding: 12px 16px;
430
+ font-size: 14px;
431
+ outline: none;
432
+ transition: border-color 0.2s ease;
433
+ }
434
+
435
+ .message-input:focus {
436
+ border-color: var(--md-sys-color-primary);
437
+ }
438
+
439
+ .send-btn {
440
+ width: 40px;
441
+ height: 40px;
442
+ border-radius: 50%;
443
+ background: linear-gradient(135deg, var(--md-sys-color-tertiary, #b85d5a) 0%, var(--md-sys-color-primary) 100%);
444
+ border: none;
445
+ color: white;
446
+ cursor: pointer;
447
+ display: flex;
448
+ align-items: center;
449
+ justify-content: center;
450
+ transition: all 0.2s ease;
451
+ }
452
+
453
+ .send-btn:hover:not(:disabled) {
454
+ transform: scale(1.05);
455
+ }
456
+
457
+ .send-btn:disabled {
458
+ opacity: 0.5;
459
+ cursor: not-allowed;
460
+ }
461
+
462
+ .loading-indicator {
463
+ display: flex;
464
+ align-items: center;
465
+ gap: 8px;
466
+ color: #666;
467
+ font-size: 12px;
468
+ }
469
+
470
+ .loading-dots {
471
+ display: flex;
472
+ gap: 4px;
473
+ }
474
+
475
+ .loading-dot {
476
+ width: 6px;
477
+ height: 6px;
478
+ border-radius: 50%;
479
+ background: var(--md-sys-color-primary);
480
+ animation: loading 1.4s infinite ease-in-out;
481
+ }
482
+
483
+ .loading-dot:nth-child(1) {
484
+ animation-delay: -0.32s;
485
+ }
486
+ .loading-dot:nth-child(2) {
487
+ animation-delay: -0.16s;
488
+ }
489
+
490
+ @keyframes loading {
491
+ 0%,
492
+ 80%,
493
+ 100% {
494
+ transform: scale(0);
495
+ }
496
+ 40% {
497
+ transform: scale(1);
498
+ }
499
+ }
500
+
501
+ /* 스크롤바 스타일링 */
502
+ .messages-container::-webkit-scrollbar {
503
+ width: 6px;
504
+ }
505
+
506
+ .messages-container::-webkit-scrollbar-track {
507
+ background: #f1f1f1;
508
+ border-radius: 3px;
509
+ }
510
+
511
+ .messages-container::-webkit-scrollbar-thumb {
512
+ background: #c1c1c1;
513
+ border-radius: 3px;
514
+ }
515
+
516
+ .messages-container::-webkit-scrollbar-thumb:hover {
517
+ background: #a8a8a8;
518
+ }
519
+
520
+ /* 근거 버튼 */
521
+ .evidence-btn {
522
+ margin-top: 8px;
523
+ display: inline-flex;
524
+ align-items: center;
525
+ gap: 6px;
526
+ border: 1px solid #d6daf0;
527
+ background: #ffffff;
528
+ color: #3b4cca;
529
+ border-radius: 14px;
530
+ padding: 6px 10px;
531
+ font-size: 12px;
532
+ cursor: pointer;
533
+ transition:
534
+ background-color 0.2s ease,
535
+ border-color 0.2s ease;
536
+ }
537
+
538
+ .evidence-btn:hover {
539
+ background-color: #f4f6ff;
540
+ border-color: #c2c8ef;
541
+ }
542
+
543
+ /* 오버레이 */
544
+ .overlay {
545
+ position: fixed;
546
+ inset: 0;
547
+ background: rgba(0, 0, 0, 0.35);
548
+ display: flex;
549
+ align-items: center;
550
+ justify-content: center;
551
+ opacity: 0;
552
+ pointer-events: none;
553
+ transition: opacity 0.2s ease;
554
+ z-index: 1100; /* 챗봇보다 위 */
555
+ }
556
+
557
+ .overlay.open {
558
+ opacity: 1;
559
+ pointer-events: auto;
560
+ }
561
+
562
+ .overlay-panel {
563
+ width: min(520px, calc(100vw - 40px));
564
+ max-height: min(70vh, 560px);
565
+ background: #ffffff;
566
+ border-radius: 14px;
567
+ box-shadow: 0 18px 60px rgba(0, 0, 0, 0.18);
568
+ display: flex;
569
+ flex-direction: column;
570
+ overflow: hidden;
571
+ }
572
+
573
+ .overlay-header {
574
+ padding: 14px 16px;
575
+ background: linear-gradient(135deg, var(--md-sys-color-tertiary, #b85d5a) 0%, var(--md-sys-color-primary) 100%);
576
+ color: #ffffff;
577
+ display: flex;
578
+ align-items: center;
579
+ justify-content: space-between;
580
+ }
581
+
582
+ .overlay-title {
583
+ font-weight: 600;
584
+ font-size: 16px;
585
+ }
586
+
587
+ .overlay-close {
588
+ background: none;
589
+ border: none;
590
+ color: #ffffff;
591
+ font-size: 26px;
592
+ width: 32px;
593
+ height: 32px;
594
+ border-radius: 50%;
595
+ cursor: pointer;
596
+ }
597
+
598
+ .overlay-body {
599
+ padding: 12px 16px 16px 16px;
600
+ overflow-y: auto;
601
+ }
602
+
603
+ .source-list {
604
+ display: flex;
605
+ flex-direction: column;
606
+ gap: 10px;
607
+ margin: 0;
608
+ padding: 0;
609
+ list-style: none;
610
+ }
611
+
612
+ .source-item {
613
+ border: 1px solid #e6e9f2;
614
+ border-radius: 10px;
615
+ padding: 10px 12px;
616
+ background: #f9fafc;
617
+ }
618
+
619
+ .source-link {
620
+ color: #1e3a8a;
621
+ text-decoration: none;
622
+ display: block;
623
+ word-break: break-all;
624
+ }
625
+
626
+ .source-link:hover {
627
+ text-decoration: underline;
628
+ }
629
+ `;
630
+ customElements.define('chatbot-widget', ChatbotWidget);
631
+ //# sourceMappingURL=chatbot-widget.js.map