(role, text, options = {})
| 1088 | }; |
| 1089 | |
| 1090 | const appendMessage = (role, text, options = {}) => { |
| 1091 | if (!logEl) return; |
| 1092 | const dark = isDarkModeEnabled(); |
| 1093 | const row = document.createElement('div'); |
| 1094 | const mine = role === 'user'; |
| 1095 | const myBg = dark ? '#1d4ed8' : '#2563eb'; |
| 1096 | const aiBg = dark ? '#181818' : '#e5e7eb'; |
| 1097 | const aiBorder = dark ? '1px solid #303030' : '1px solid #d1d5db'; |
| 1098 | row.style.alignSelf = 'stretch'; |
| 1099 | row.style.display = 'flex'; |
| 1100 | row.style.justifyContent = mine ? 'flex-end' : 'flex-start'; |
| 1101 | const column = document.createElement('div'); |
| 1102 | column.style.maxWidth = 'min(88%, 640px)'; |
| 1103 | column.style.display = 'flex'; |
| 1104 | column.style.flexDirection = 'column'; |
| 1105 | column.style.gap = '4px'; |
| 1106 | column.style.alignItems = mine ? 'flex-end' : 'flex-start'; |
| 1107 | |
| 1108 | const label = document.createElement('div'); |
| 1109 | label.style.fontSize = '11px'; |
| 1110 | label.style.opacity = '.58'; |
| 1111 | label.style.padding = '0 2px'; |
| 1112 | label.textContent = mine ? 'You' : 'AI'; |
| 1113 | |
| 1114 | const bubble = document.createElement('div'); |
| 1115 | bubble.style.padding = '11px 14px'; |
| 1116 | bubble.style.borderRadius = mine ? '18px 18px 6px 18px' : '18px 18px 18px 6px'; |
| 1117 | bubble.style.background = mine ? myBg : aiBg; |
| 1118 | bubble.style.border = mine ? 'none' : aiBorder; |
| 1119 | bubble.style.color = mine ? '#ffffff' : (dark ? '#f3f5f7' : '#111827'); |
| 1120 | bubble.style.whiteSpace = 'pre-wrap'; |
| 1121 | bubble.style.wordBreak = 'break-word'; |
| 1122 | bubble.style.lineHeight = '1.45'; |
| 1123 | bubble.style.boxShadow = mine ? '0 10px 24px rgba(37,99,235,.18)' : '0 1px 2px rgba(15,23,42,.04)'; |
| 1124 | |
| 1125 | const textEl = document.createElement('div'); |
| 1126 | textEl.textContent = String(text || ''); |
| 1127 | bubble.appendChild(textEl); |
| 1128 | |
| 1129 | const workflowEl = document.createElement('div'); |
| 1130 | if (options.workflow) { |
| 1131 | workflowEl.innerHTML = buildWorkflowCard(options.workflow); |
| 1132 | } |
| 1133 | bubble.appendChild(workflowEl); |
| 1134 | |
| 1135 | column.appendChild(label); |
| 1136 | column.appendChild(bubble); |
| 1137 | row.appendChild(column); |
| 1138 | logEl.appendChild(row); |
| 1139 | scrollLogToBottom(); |
| 1140 | return { |
| 1141 | row, |
| 1142 | setText(nextText) { |
| 1143 | textEl.textContent = String(nextText || ''); |
| 1144 | }, |
| 1145 | setWorkflow(nextWorkflow) { |
| 1146 | workflowEl.innerHTML = nextWorkflow ? buildWorkflowCard(nextWorkflow) : ''; |
| 1147 | } |
no test coverage detected