├── .gitignore ├── README.md ├── dist └── build │ └── static │ └── js │ └── bundle.min.js ├── package-lock.json ├── package.json ├── public └── index.html ├── src ├── chatPlaceholder │ └── index.tsx ├── chatWidget │ ├── chatTrigger │ │ └── index.tsx │ ├── chatWindow │ │ ├── chatMessage │ │ │ └── index.tsx │ │ └── index.tsx │ ├── index.tsx │ └── utils.ts ├── controllers │ └── index.ts ├── index.tsx ├── react-app-env.d.ts ├── reportWebVitals.ts ├── setupTests.ts └── types │ └── chatWidget │ └── index.ts ├── tsconfig.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Langflow Embedded Chat ⛓️ 2 | 3 | Welcome to the Langflow Embedded Chat repository! 🎉 4 | 5 | The Langflow Embedded Chat is a powerful web component that enables seamless communication with the [Langflow ⛓️](https://github.com/logspace-ai/langflow). This widget provides a chat interface, allowing you to integrate Langflow ⛓️ into your web applications effortlessly. 6 | 7 | [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 8 | 9 | ## What is Langflow? 10 | 11 | Langflow is a no-code open-source project that empowers developers to build cutting-edge applications using Language Model technologies. With Langflow, you can leverage the power of LLMs (Large Language Models) to enhance user interactions, generate human-like text, and gain valuable insights from natural language data. 12 | 13 | ## Features 14 | 15 | 🌟 Seamless Integration: Easily integrate the Langflow Widget into your website or web application with just a few lines of JavaScript. 16 | 17 | 🚀 Interactive Chat Interface: Engage your users with a user-friendly chat interface, powered by Langflow's advanced language understanding capabilities. 18 | 19 | 🎛️ Customizable Styling: Customize the appearance of the chat widget to match your application's design and branding. 20 | 21 | 🌐 Multilingual Support: Communicate with users in multiple languages, opening up your application to a global audience. 22 | 23 | ## Installation 24 | 25 | ### Option 1: CDN Link 26 | 27 | Use the Langflow Widget directly from the CDN by including the following script tag in your HTML: 28 | 29 | ```html 30 | 31 | ``` 32 | 33 | ### Option 2: Local Build 34 | 35 | 1. Clone this repository to your local machine: 36 | 37 | ```bash 38 | git clone https://github.com/logspace-ai/langflow-embedded-chat.git 39 | ``` 40 | 41 | 2. Navigate to the project directory: 42 | 43 | ```bash 44 | cd langflow-embedded-chat 45 | ``` 46 | 47 | 3. Build the project to generate the bundle: 48 | 49 | ```bash 50 | npm run build 51 | ``` 52 | 53 | 5. After the build process completes, you'll find the bundle in the `dist/build/static/js` folder. You can include this JavaScript file in your HTML: 54 | 55 | ```html 56 | 57 | ``` 58 | 59 | ## Usage 60 | 61 | ### on simple HTML 62 | ```html 63 | 64 | 65 | 66 | 67 | 68 | 72 | 73 | 74 | ``` 75 | 76 | ### on React 77 | Import the js bundle in the index.html of your react project 78 | ```html 79 | 80 | ``` 81 | Encapsulate your custom element in a react component 82 | ```html 83 | export default function ChatWidget() { 84 | return ( 85 |
86 | 89 |
90 | ); 91 | } 92 | ``` 93 | 94 | ## Configuration 95 | 96 | Use the widget API to customize your widget: 97 | 98 | | Prop | Type | Required | 99 | |-----------------------|-----------|----------| 100 | | api_key | string | No | 101 | | bot_message_style | json | No | 102 | | chat_position | string | No | 103 | | chat_trigger_style | json | No | 104 | | chat_window_style | json | No | 105 | | output_type | string | No | 106 | | input_type | string | No | 107 | | output_component | string | No | 108 | | error_message_style | json | No | 109 | | flow_id | string | Yes | 110 | | height | number | No | 111 | | host_url | string | Yes | 112 | | input_container_style | json | No | 113 | | input_style | json | No | 114 | | online | boolean | No | 115 | | start_open | boolean | No | 116 | | online_message | string | No | 117 | | placeholder | string | No | 118 | | placeholder_sending | string | No | 119 | | send_button_style | json | No | 120 | | send_icon_style | json | No | 121 | | tweaks | json | No | 122 | | user_message_style | json | No | 123 | | width | number | No | 124 | | window_title | string | No | 125 | | session_id | string | No | 126 | | additional_headers | json | No | 127 | 128 | - **api_key:** 129 | - Type: String 130 | - Required: No 131 | - Description: X-API-Key header to send to Langflow 132 | 133 | 134 | - **bot_message_style:** 135 | - Type: JSON 136 | - Required: No 137 | - Description: Styling options for formatting bot messages in the chat window. 138 | 139 | - **input_type:** 140 | - Type: String 141 | - Required: No 142 | - Description: Specifies the input type for chat messages. 143 | 144 | - **output_type:** 145 | - Type: String 146 | - Required: No 147 | - Description: Specifies the output type for chat messages. 148 | 149 | - **output_component:** 150 | - Type: String 151 | - Required: No 152 | - Description: Specify the output ID for chat messages; this is necessary when multiple outputs are present. 153 | 154 | - **chat_position:** 155 | - Type: String 156 | - Required: No 157 | - Description: Determines the position of the chat window (top-left, top-center, top-right, center-left, center-right, bottom-right, bottom-center, bottom-left). 158 | 159 | - **chat_trigger_style:** 160 | - Type: JSON 161 | - Required: No 162 | - Description: Styling options for the chat trigger. 163 | 164 | - **chat_window_style:** 165 | - Type: JSON 166 | - Required: No 167 | - Description: Styling options for the overall chat window. 168 | 169 | - **error_message_style:** 170 | - Type: JSON 171 | - Required: No 172 | - Description: Styling options for error messages in the chat window. 173 | 174 | - **flow_id:** 175 | - Type: String 176 | - Required: Yes 177 | - Description: Identifier for the flow associated with the component. 178 | 179 | - **height:** 180 | - Type: Number 181 | - Required: No 182 | - Description: Specifies the height of the chat window in pixels. 183 | 184 | - **host_url:** 185 | - Type: String 186 | - Required: Yes 187 | - Description: The URL of the host for communication with the chat component. 188 | 189 | - **input_container_style:** 190 | - Type: JSON 191 | - Required: No 192 | - Description: Styling options for the input container where chat messages are typed. 193 | 194 | - **input_style:** 195 | - Type: JSON 196 | - Required: No 197 | - Description: Styling options for the chat input field. 198 | 199 | - **Online:** 200 | - Type: Boolean 201 | - Required: No 202 | - Description: Indicates if the chat component is online or offline. 203 | 204 | - **start_open:** 205 | - Type: Boolean 206 | - Required: No 207 | - Description: Indicates if the chat window should be open by default. 208 | 209 | - **online_message:** 210 | - Type: String 211 | - Required: No 212 | - Description: Custom message to display when the chat component is online. 213 | 214 | - **placeholder:** 215 | - Type: String 216 | - Required: No 217 | - Description: Placeholder text for the chat input field. 218 | 219 | - **placeholder_sending:** 220 | - Type: String 221 | - Required: No 222 | - Description: Placeholder text to display while a message is being sent. 223 | 224 | - **send_button_style:** 225 | - Type: JSON 226 | - Required: No 227 | - Description: Styling options for the send button in the chat window. 228 | 229 | - **send_icon_style:** 230 | - Type: JSON 231 | - Required: No 232 | - Description: Styling options for the send icon in the chat window. 233 | 234 | - **tweaks:** 235 | - Type: JSON 236 | - Required: No 237 | - Description: Additional custom tweaks for the associated flow. 238 | 239 | - **user_message_style:** 240 | - Type: JSON 241 | - Required: No 242 | - Description: Styling options for formatting user messages in the chat window. 243 | 244 | - **width:** 245 | - Type: Number 246 | - Required: No 247 | - Description: Specifies the width of the chat window in pixels. 248 | 249 | - **window_title:** 250 | - Type: String 251 | - Required: No 252 | - Description: Title for the chat window, displayed in the header or title bar. 253 | 254 | - **session_id:** 255 | - Type: String 256 | - Required: No 257 | - Description: Custom session id to override the random session id used as default. 258 | 259 | - **additional_headers:** 260 | - Type: JSON 261 | - Required: No 262 | - Description: Additional headers to be sent to Langflow server 263 | 264 | 265 | ## Live example: 266 | Try out or [live example](https://codesandbox.io/s/langflow-embedded-chat-example-dv9zpx) to see how the Langflow Embedded Chat ⛓️ works. 267 | 268 | 1. first create a Flow and save it using [Langflow ⛓️](https://github.com/logspace-ai/langflow). 269 | 2. Get the hosted URL to use in the live example. 270 | 3. If you are using a public host (like [Hugging Face Spaces](https://huggingface.co/spaces/Logspace/Langflow)) use tweaks to keep your API keys safe. 271 | 272 | ## License 273 | 274 | This project is licensed under the [MIT License](https://opensource.org/licenses/MIT) - see the [LICENSE](https://github.com/logspace-ai/langflow-embedded-chat/tree/main/LICENSE) file for details. 275 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "langflow-embedded-chat", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@r2wc/react-to-web-component": "^2.0.2", 7 | "@testing-library/jest-dom": "^5.16.5", 8 | "@testing-library/react": "^13.4.0", 9 | "@testing-library/user-event": "^13.5.0", 10 | "@types/jest": "^27.5.2", 11 | "@types/node": "^16.18.37", 12 | "@types/react": "^18.2.14", 13 | "@types/react-dom": "^18.2.6", 14 | "axios": "^1.4.0", 15 | "lucide-react": "^0.256.0", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "react-markdown": "^8.0.7", 19 | "react-scripts": "5.0.1", 20 | "react-shadow": "^20.3.0", 21 | "rehype-mathjax": "^4.0.3", 22 | "remark-gfm": "3.0.1", 23 | "typescript": "^4.9.5", 24 | "uglifyjs-webpack-plugin": "^2.2.0", 25 | "uuid": "^10.0.0", 26 | "web-vitals": "^2.1.4" 27 | }, 28 | "scripts": { 29 | "start": "react-scripts start", 30 | "build": "npm install --legacy-peer-deps && npm run build:react && npm run build:bundle", 31 | "build:react": "react-scripts build", 32 | "build:bundle": "webpack --config webpack.config.js", 33 | "test": "react-scripts test", 34 | "eject": "react-scripts eject" 35 | }, 36 | "eslintConfig": { 37 | "extends": [ 38 | "react-app", 39 | "react-app/jest" 40 | ] 41 | }, 42 | "browserslist": { 43 | "production": [ 44 | ">0.2%", 45 | "not dead", 46 | "not op_mini all" 47 | ], 48 | "development": [ 49 | "last 1 chrome version", 50 | "last 1 firefox version", 51 | "last 1 safari version" 52 | ] 53 | }, 54 | "devDependencies": { 55 | "webpack-cli": "^5.1.4" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /src/chatPlaceholder/index.tsx: -------------------------------------------------------------------------------- 1 | import { MoreHorizontal } from "lucide-react"; 2 | import { ChatMessagePlaceholderType } from "../types/chatWidget"; 3 | 4 | export default function ChatMessagePlaceholder({ 5 | bot_message_style, 6 | }: ChatMessagePlaceholderType) { 7 | return ( 8 |
11 |
12 |
13 | 14 |
15 |
16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/chatWidget/chatTrigger/index.tsx: -------------------------------------------------------------------------------- 1 | import { MessageSquare, X } from "lucide-react" 2 | export default function ChatTrigger({ style, open, setOpen, triggerRef }: { style?: React.CSSProperties, open: boolean, setOpen: Function, triggerRef: React.RefObject | null }) { 3 | 4 | return ( 5 | 14 | ) 15 | } -------------------------------------------------------------------------------- /src/chatWidget/chatWindow/chatMessage/index.tsx: -------------------------------------------------------------------------------- 1 | import Markdown from "react-markdown"; 2 | import { ChatMessageType } from "../../../types/chatWidget"; 3 | import remarkGfm from "remark-gfm"; 4 | import rehypeMathjax from "rehype-mathjax"; 5 | 6 | export default function ChatMessage({ 7 | message, 8 | isSend, 9 | error, 10 | user_message_style, 11 | bot_message_style, 12 | error_message_style, 13 | }: ChatMessageType) { 14 | 15 | return ( 16 |
21 | {isSend ? ( 22 |
23 | {message} 24 |
25 | ) : error ? ( 26 |
27 | {message} 28 |
29 | ) : ( 30 |
31 | 36 | {message} 37 | 38 |
39 | )} 40 |
41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/chatWidget/chatWindow/index.tsx: -------------------------------------------------------------------------------- 1 | import { Send } from "lucide-react"; 2 | import { extractMessageFromOutput, getAnimationOrigin, getChatPosition } from "../utils"; 3 | import React, { useEffect, useRef, useState } from "react"; 4 | import { ChatMessageType } from "../../types/chatWidget"; 5 | import ChatMessage from "./chatMessage"; 6 | import { sendMessage } from "../../controllers"; 7 | import ChatMessagePlaceholder from "../../chatPlaceholder"; 8 | 9 | export default function ChatWindow({ 10 | api_key, 11 | flowId, 12 | hostUrl, 13 | updateLastMessage, 14 | messages, 15 | output_type, 16 | input_type, 17 | output_component, 18 | bot_message_style, 19 | send_icon_style, 20 | user_message_style, 21 | chat_window_style, 22 | error_message_style, 23 | placeholder_sending, 24 | send_button_style, 25 | online = true, 26 | open, 27 | online_message = "We'll reply as soon as we can", 28 | offline_message = "We're offline now", 29 | window_title = "Chat", 30 | placeholder, 31 | input_style, 32 | input_container_style, 33 | addMessage, 34 | position, 35 | triggerRef, 36 | width = 450, 37 | height = 650, 38 | tweaks, 39 | sessionId, 40 | additional_headers 41 | }: { 42 | api_key?: string; 43 | output_type: string, 44 | input_type: string, 45 | output_component?: string, 46 | bot_message_style?: React.CSSProperties; 47 | send_icon_style?: React.CSSProperties; 48 | user_message_style?: React.CSSProperties; 49 | chat_window_style?: React.CSSProperties; 50 | error_message_style?: React.CSSProperties; 51 | send_button_style?: React.CSSProperties; 52 | online?: boolean; 53 | open: boolean; 54 | online_message?: string; 55 | placeholder_sending?: string; 56 | offline_message?: string; 57 | window_title?: string; 58 | placeholder?: string; 59 | input_style?: React.CSSProperties; 60 | input_container_style?: React.CSSProperties; 61 | tweaks?: { [key: string]: any }; 62 | flowId: string; 63 | hostUrl: string; 64 | updateLastMessage: Function; 65 | messages: ChatMessageType[]; 66 | addMessage: Function; 67 | position?: string; 68 | triggerRef: React.RefObject; 69 | width?: number; 70 | height?: number; 71 | sessionId: React.MutableRefObject; 72 | additional_headers?: { [key: string]: string }; 73 | 74 | }) { 75 | const [value, setValue] = useState(""); 76 | const ref = useRef(null); 77 | const lastMessage = useRef(null); 78 | const [windowPosition, setWindowPosition] = useState({ left: "0", top: "0" }); 79 | const inputRef = useRef(null); /* User input Ref */ 80 | useEffect(() => { 81 | if (triggerRef) 82 | setWindowPosition( 83 | getChatPosition( 84 | triggerRef.current!.getBoundingClientRect(), 85 | width, 86 | height, 87 | position 88 | ) 89 | ); 90 | }, [triggerRef, width, height, position]); 91 | 92 | /* Initial listener for loss of focus that refocuses User input after a small delay */ 93 | 94 | const [sendingMessage, setSendingMessage] = useState(false); 95 | 96 | function handleClick() { 97 | if (value && value.trim() !== "") { 98 | addMessage({ message: value, isSend: true }); 99 | setSendingMessage(true); 100 | setValue(""); 101 | sendMessage(hostUrl, flowId, value, input_type, output_type, sessionId, output_component, tweaks, api_key, additional_headers) 102 | .then((res) => { 103 | if ( 104 | res.data && 105 | res.data.outputs && 106 | Object.keys(res.data.outputs).length > 0 && 107 | res.data.outputs[0].outputs && res.data.outputs[0].outputs.length > 0 108 | ) { 109 | const flowOutputs: Array = res.data.outputs[0].outputs; 110 | if (output_component && 111 | flowOutputs.map(e => e.component_id).includes(output_component)) { 112 | Object.values(flowOutputs.find(e => e.component_id === output_component).outputs).forEach((output: any) => { 113 | addMessage({ 114 | message: extractMessageFromOutput(output), 115 | isSend: false, 116 | }); 117 | }) 118 | } else if ( 119 | flowOutputs.length === 1 120 | ) { 121 | Object.values(flowOutputs[0].outputs).forEach((output: any) => { 122 | addMessage({ 123 | message: extractMessageFromOutput(output), 124 | isSend: false, 125 | }); 126 | }) 127 | } else { 128 | flowOutputs 129 | .sort((a, b) => { 130 | // Get the earliest timestamp from each flowOutput's outputs 131 | const aTimestamp = Math.min(...Object.values(a.outputs).map((output: any) => Date.parse(output.message?.timestamp))); 132 | const bTimestamp = Math.min(...Object.values(b.outputs).map((output: any) => Date.parse(output.message?.timestamp))); 133 | return aTimestamp - bTimestamp; // Sort descending (newest first) 134 | }) 135 | .forEach((flowOutput) => { 136 | Object.values(flowOutput.outputs).forEach((output: any) => { 137 | addMessage({ 138 | message: extractMessageFromOutput(output), 139 | isSend: false, 140 | }); 141 | }); 142 | }); 143 | } 144 | } 145 | if (res.data && res.data.session_id) { 146 | sessionId.current = res.data.session_id; 147 | } 148 | setSendingMessage(false); 149 | }) 150 | .catch((err) => { 151 | const response = err.response; 152 | if (err.code === "ERR_NETWORK") { 153 | updateLastMessage({ 154 | message: "Network error", 155 | isSend: false, 156 | error: true, 157 | }); 158 | } else if ( 159 | response && 160 | response.status === 500 && 161 | response.data && 162 | response.data.detail 163 | ) { 164 | updateLastMessage({ 165 | message: response.data.detail, 166 | isSend: false, 167 | error: true, 168 | }); 169 | } 170 | console.error(err); 171 | setSendingMessage(false); 172 | }); 173 | } 174 | } 175 | 176 | useEffect(() => { 177 | if (lastMessage.current) 178 | lastMessage.current.scrollIntoView({ behavior: "smooth" }); 179 | }, [messages]); 180 | 181 | /* Refocus the User input whenever a new response is returned from the LLM */ 182 | 183 | useEffect(() => { 184 | // after a slight delay 185 | setTimeout(() => { 186 | inputRef.current?.focus(); 187 | }, 100); 188 | }, [messages, open]); 189 | 190 | return ( 191 |
199 |
204 |
205 | {window_title} 206 |
207 | {online ? ( 208 | <> 209 |
210 | {online_message} 211 | 212 | ) : ( 213 | <> 214 |
215 | {offline_message} 216 | 217 | )} 218 |
219 |
220 |
221 | {messages.map((message, index) => ( 222 | 231 | ))} 232 | {sendingMessage && ( 233 | 234 | )} 235 |
236 |
237 |
238 | setValue(e.target.value)} 241 | onKeyDown={(e) => { 242 | if (e.key === "Enter") handleClick(); 243 | }} 244 | type="text" 245 | disabled={sendingMessage} 246 | placeholder={sendingMessage ? (placeholder_sending || "Thinking...") : (placeholder || "Type your message...")} 247 | style={input_style} 248 | ref={inputRef} 249 | className="cl-input-element" 250 | /> 251 | 266 |
267 |
268 |
269 | ); 270 | } 271 | -------------------------------------------------------------------------------- /src/chatWidget/index.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import ChatTrigger from "./chatTrigger"; 3 | import ChatWindow from "./chatWindow"; 4 | import { ChatMessageType } from "../types/chatWidget"; 5 | const { v4: uuidv4 } = require('uuid'); 6 | 7 | export default function ChatWidget({ 8 | api_key, 9 | output_type = "chat", 10 | input_type = "chat", 11 | output_component, 12 | chat_trigger_style, 13 | host_url, 14 | flow_id, 15 | tweaks, 16 | send_icon_style, 17 | bot_message_style, 18 | user_message_style, 19 | chat_window_style, 20 | height, 21 | width, 22 | error_message_style, 23 | send_button_style, 24 | online, 25 | online_message, 26 | offline_message, 27 | window_title, 28 | chat_position, 29 | placeholder, 30 | input_style, 31 | placeholder_sending, 32 | input_container_style, 33 | additional_headers, 34 | session_id, 35 | start_open=false, 36 | }: { 37 | api_key?: string; 38 | input_value: string, 39 | output_type: string, 40 | input_type: string, 41 | output_component?: string; 42 | send_icon_style?: React.CSSProperties; 43 | chat_position?: string; 44 | chat_trigger_style?: React.CSSProperties; 45 | bot_message_style?: React.CSSProperties; 46 | user_message_style?: React.CSSProperties; 47 | chat_window_style?: React.CSSProperties; 48 | online?: boolean; 49 | online_message?: string; 50 | offline_message?: string; 51 | height?: number; 52 | width?: number; 53 | window_title?: string; 54 | error_message_style?: React.CSSProperties; 55 | send_button_style?: React.CSSProperties; 56 | placeholder_sending?: string; 57 | placeholder?: string; 58 | input_style?: React.CSSProperties; 59 | input_container_style?: React.CSSProperties; 60 | host_url: string; 61 | flow_id: string; 62 | tweaks?: { [key: string]: any }; 63 | additional_headers?: { [key: string]: string }; 64 | session_id?: string; 65 | start_open?: boolean; 66 | }) { 67 | const [open, setOpen] = useState(start_open); 68 | const [messages, setMessages] = useState([]); 69 | const sessionId = useRef(session_id ?? uuidv4()); 70 | function updateLastMessage(message: ChatMessageType) { 71 | setMessages((prev) => { 72 | prev[prev.length - 1] = message; 73 | return [...prev]; 74 | }); 75 | } 76 | function addMessage(message: ChatMessageType) { 77 | setMessages((prev) => [...prev, message]); 78 | } 79 | const triggerRef = useRef(null); 80 | 81 | const styles = ` 82 | /* 83 | ! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com 84 | */ 85 | 86 | /* 87 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 88 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 89 | */ 90 | 91 | *, 92 | ::before, 93 | ::after { 94 | box-sizing: border-box; 95 | /* 1 */ 96 | border-width: 0; 97 | /* 2 */ 98 | border-style: solid; 99 | /* 2 */ 100 | border-color: #e5e7eb; 101 | /* 2 */ 102 | } 103 | 104 | ::before, 105 | ::after { 106 | --tw-content: ''; 107 | } 108 | 109 | /* 110 | 1. Use a consistent sensible line-height in all browsers. 111 | 2. Prevent adjustments of font size after orientation changes in iOS. 112 | 3. Use a more readable tab size. 113 | 4. Use the user's configured 'sans' font-family by default. 114 | 5. Use the user's configured 'sans' font-feature-settings by default. 115 | 6. Use the user's configured 'sans' font-variation-settings by default. 116 | */ 117 | 118 | html { 119 | line-height: 1.5; 120 | /* 1 */ 121 | -webkit-text-size-adjust: 100%; 122 | /* 2 */ 123 | /* 3 */ 124 | tab-size: 4; 125 | /* 3 */ 126 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 127 | /* 4 */ 128 | -webkit-font-feature-settings: normal; 129 | font-feature-settings: normal; 130 | /* 5 */ 131 | font-variation-settings: normal; 132 | /* 6 */ 133 | } 134 | 135 | /* 136 | 1. Remove the margin in all browsers. 137 | 2. Inherit line-height from 'html' so users can set them as a class directly on the 'html' element. 138 | */ 139 | 140 | body { 141 | margin: 0; 142 | /* 1 */ 143 | line-height: inherit; 144 | /* 2 */ 145 | } 146 | 147 | /* 148 | 1. Add the correct height in Firefox. 149 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 150 | 3. Ensure horizontal rules are visible by default. 151 | */ 152 | 153 | /* 154 | Add the correct text decoration in Chrome, Edge, and Safari. 155 | */ 156 | 157 | abbr:where([title]) { 158 | -webkit-text-decoration: underline dotted; 159 | text-decoration: underline dotted; 160 | } 161 | 162 | /* 163 | Remove the default font size and weight for headings. 164 | */ 165 | 166 | /* 167 | Add the correct font weight in Edge and Safari. 168 | */ 169 | 170 | b, 171 | strong { 172 | font-weight: bolder; 173 | } 174 | 175 | /* 176 | 1. Use the user's configured 'mono' font family by default. 177 | 2. Correct the odd 'em' font sizing in all browsers. 178 | */ 179 | 180 | code, 181 | kbd, 182 | samp, 183 | pre { 184 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 185 | /* 1 */ 186 | font-size: 1em; 187 | /* 2 */ 188 | } 189 | 190 | /* 191 | Add the correct font size in all browsers. 192 | */ 193 | 194 | small { 195 | font-size: 80%; 196 | } 197 | 198 | /* 199 | Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. 200 | */ 201 | 202 | sub, 203 | sup { 204 | font-size: 75%; 205 | line-height: 0; 206 | position: relative; 207 | vertical-align: baseline; 208 | } 209 | 210 | sub { 211 | bottom: -0.25em; 212 | } 213 | 214 | sup { 215 | top: -0.5em; 216 | } 217 | 218 | /* 219 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 220 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 221 | 3. Remove gaps between table borders by default. 222 | */ 223 | 224 | 225 | 226 | /* 227 | 1. Change the font styles in all browsers. 228 | 2. Remove the margin in Firefox and Safari. 229 | 3. Remove default padding in all browsers. 230 | */ 231 | 232 | button, 233 | input, 234 | optgroup, 235 | select, 236 | textarea { 237 | font-family: inherit; 238 | /* 1 */ 239 | font-size: 100%; 240 | /* 1 */ 241 | font-weight: inherit; 242 | /* 1 */ 243 | line-height: inherit; 244 | /* 1 */ 245 | color: inherit; 246 | /* 1 */ 247 | margin: 0; 248 | /* 2 */ 249 | padding: 0; 250 | /* 3 */ 251 | } 252 | 253 | /* 254 | Remove the inheritance of text transform in Edge and Firefox. 255 | */ 256 | 257 | button, 258 | select { 259 | text-transform: none; 260 | } 261 | 262 | /* 263 | 1. Correct the inability to style clickable types in iOS and Safari. 264 | 2. Remove default button styles. 265 | */ 266 | 267 | button, 268 | [type='button'], 269 | [type='reset'], 270 | [type='submit'] { 271 | -webkit-appearance: button; 272 | /* 1 */ 273 | background-color: transparent; 274 | /* 2 */ 275 | background-image: none; 276 | /* 2 */ 277 | } 278 | 279 | /* 280 | Use the modern Firefox focus style for all focusable elements. 281 | */ 282 | 283 | :-moz-focusring { 284 | outline: auto; 285 | } 286 | 287 | /* 288 | Remove the additional ':invalid' styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 289 | */ 290 | 291 | :-moz-ui-invalid { 292 | box-shadow: none; 293 | } 294 | 295 | /* 296 | Add the correct vertical alignment in Chrome and Firefox. 297 | */ 298 | 299 | progress { 300 | vertical-align: baseline; 301 | } 302 | 303 | /* 304 | Correct the cursor style of increment and decrement buttons in Safari. 305 | */ 306 | 307 | ::-webkit-inner-spin-button, 308 | ::-webkit-outer-spin-button { 309 | height: auto; 310 | } 311 | 312 | /* 313 | 1. Correct the odd appearance in Chrome and Safari. 314 | 2. Correct the outline style in Safari. 315 | */ 316 | 317 | [type='search'] { 318 | -webkit-appearance: textfield; 319 | /* 1 */ 320 | outline-offset: -2px; 321 | /* 2 */ 322 | } 323 | 324 | /* 325 | Remove the inner padding in Chrome and Safari on macOS. 326 | */ 327 | 328 | ::-webkit-search-decoration { 329 | -webkit-appearance: none; 330 | } 331 | 332 | /* 333 | 1. Correct the inability to style clickable types in iOS and Safari. 334 | 2. Change font properties to 'inherit' in Safari. 335 | */ 336 | 337 | ::-webkit-file-upload-button { 338 | -webkit-appearance: button; 339 | /* 1 */ 340 | font: inherit; 341 | /* 2 */ 342 | } 343 | 344 | /* 345 | Add the correct display in Chrome and Safari. 346 | */ 347 | 348 | summary { 349 | display: list-item; 350 | } 351 | 352 | /* 353 | Removes the default spacing and border for appropriate elements. 354 | */ 355 | 356 | fieldset { 357 | margin: 0; 358 | padding: 0; 359 | } 360 | 361 | legend { 362 | padding: 0; 363 | } 364 | 365 | 366 | /* 367 | Prevent resizing textareas horizontally by default. 368 | */ 369 | 370 | textarea { 371 | resize: vertical; 372 | } 373 | 374 | /* 375 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 376 | 2. Set the default placeholder color to the user's configured gray 400 color. 377 | */ 378 | 379 | input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { 380 | opacity: 1; 381 | /* 1 */ 382 | color: #9ca3af; 383 | /* 2 */ 384 | } 385 | 386 | input::placeholder, 387 | textarea::placeholder { 388 | opacity: 1; 389 | /* 1 */ 390 | color: #9ca3af; 391 | /* 2 */ 392 | } 393 | 394 | /* 395 | Set the default cursor for buttons. 396 | */ 397 | 398 | button, 399 | [role="button"] { 400 | cursor: pointer; 401 | } 402 | 403 | /* 404 | Make sure disabled buttons don't get the pointer cursor. 405 | */ 406 | 407 | :disabled { 408 | cursor: default; 409 | } 410 | 411 | /* 412 | 1. Make replaced elements 'display: block' by default. (https://github.com/mozdevs/cssremedy/issues/14) 413 | 2. Add 'vertical-align: middle' to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 414 | This can trigger a poorly considered lint error in some tools but is included by design. 415 | */ 416 | 417 | img, 418 | svg, 419 | video, 420 | canvas, 421 | audio, 422 | iframe, 423 | embed, 424 | object { 425 | display: block; 426 | /* 1 */ 427 | vertical-align: middle; 428 | /* 2 */ 429 | } 430 | 431 | /* 432 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 433 | */ 434 | 435 | img, 436 | video { 437 | max-width: 100%; 438 | height: auto; 439 | } 440 | 441 | /* Make elements with the HTML hidden attribute stay hidden by default */ 442 | 443 | [hidden] { 444 | display: none; 445 | } 446 | 447 | *, ::before, ::after { 448 | --tw-border-spacing-x: 0; 449 | --tw-border-spacing-y: 0; 450 | --tw-translate-x: 0; 451 | --tw-translate-y: 0; 452 | --tw-rotate: 0; 453 | --tw-skew-x: 0; 454 | --tw-skew-y: 0; 455 | --tw-scale-x: 1; 456 | --tw-scale-y: 1; 457 | --tw-pan-x: ; 458 | --tw-pan-y: ; 459 | --tw-pinch-zoom: ; 460 | --tw-scroll-snap-strictness: proximity; 461 | --tw-gradient-from-position: ; 462 | --tw-gradient-via-position: ; 463 | --tw-gradient-to-position: ; 464 | --tw-ordinal: ; 465 | --tw-slashed-zero: ; 466 | --tw-numeric-figure: ; 467 | --tw-numeric-spacing: ; 468 | --tw-numeric-fraction: ; 469 | --tw-ring-inset: ; 470 | --tw-ring-offset-width: 0px; 471 | --tw-ring-offset-color: #fff; 472 | --tw-ring-color: rgb(59 130 246 / 0.5); 473 | --tw-ring-offset-shadow: 0 0 #0000; 474 | --tw-ring-shadow: 0 0 #0000; 475 | --tw-shadow: 0 0 #0000; 476 | --tw-shadow-colored: 0 0 #0000; 477 | --tw-blur: ; 478 | --tw-brightness: ; 479 | --tw-contrast: ; 480 | --tw-grayscale: ; 481 | --tw-hue-rotate: ; 482 | --tw-invert: ; 483 | --tw-saturate: ; 484 | --tw-sepia: ; 485 | --tw-drop-shadow: ; 486 | --tw-backdrop-blur: ; 487 | --tw-backdrop-brightness: ; 488 | --tw-backdrop-contrast: ; 489 | --tw-backdrop-grayscale: ; 490 | --tw-backdrop-hue-rotate: ; 491 | --tw-backdrop-invert: ; 492 | --tw-backdrop-opacity: ; 493 | --tw-backdrop-saturate: ; 494 | --tw-backdrop-sepia: ; 495 | } 496 | 497 | ::-webkit-backdrop { 498 | --tw-border-spacing-x: 0; 499 | --tw-border-spacing-y: 0; 500 | --tw-translate-x: 0; 501 | --tw-translate-y: 0; 502 | --tw-rotate: 0; 503 | --tw-skew-x: 0; 504 | --tw-skew-y: 0; 505 | --tw-scale-x: 1; 506 | --tw-scale-y: 1; 507 | --tw-pan-x: ; 508 | --tw-pan-y: ; 509 | --tw-pinch-zoom: ; 510 | --tw-scroll-snap-strictness: proximity; 511 | --tw-gradient-from-position: ; 512 | --tw-gradient-via-position: ; 513 | --tw-gradient-to-position: ; 514 | --tw-ordinal: ; 515 | --tw-slashed-zero: ; 516 | --tw-numeric-figure: ; 517 | --tw-numeric-spacing: ; 518 | --tw-numeric-fraction: ; 519 | --tw-ring-inset: ; 520 | --tw-ring-offset-width: 0px; 521 | --tw-ring-offset-color: #fff; 522 | --tw-ring-color: rgb(59 130 246 / 0.5); 523 | --tw-ring-offset-shadow: 0 0 #0000; 524 | --tw-ring-shadow: 0 0 #0000; 525 | --tw-shadow: 0 0 #0000; 526 | --tw-shadow-colored: 0 0 #0000; 527 | --tw-blur: ; 528 | --tw-brightness: ; 529 | --tw-contrast: ; 530 | --tw-grayscale: ; 531 | --tw-hue-rotate: ; 532 | --tw-invert: ; 533 | --tw-saturate: ; 534 | --tw-sepia: ; 535 | --tw-drop-shadow: ; 536 | --tw-backdrop-blur: ; 537 | --tw-backdrop-brightness: ; 538 | --tw-backdrop-contrast: ; 539 | --tw-backdrop-grayscale: ; 540 | --tw-backdrop-hue-rotate: ; 541 | --tw-backdrop-invert: ; 542 | --tw-backdrop-opacity: ; 543 | --tw-backdrop-saturate: ; 544 | --tw-backdrop-sepia: ; 545 | } 546 | 547 | ::backdrop { 548 | --tw-border-spacing-x: 0; 549 | --tw-border-spacing-y: 0; 550 | --tw-translate-x: 0; 551 | --tw-translate-y: 0; 552 | --tw-rotate: 0; 553 | --tw-skew-x: 0; 554 | --tw-skew-y: 0; 555 | --tw-scale-x: 1; 556 | --tw-scale-y: 1; 557 | --tw-pan-x: ; 558 | --tw-pan-y: ; 559 | --tw-pinch-zoom: ; 560 | --tw-scroll-snap-strictness: proximity; 561 | --tw-gradient-from-position: ; 562 | --tw-gradient-via-position: ; 563 | --tw-gradient-to-position: ; 564 | --tw-ordinal: ; 565 | --tw-slashed-zero: ; 566 | --tw-numeric-figure: ; 567 | --tw-numeric-spacing: ; 568 | --tw-numeric-fraction: ; 569 | --tw-ring-inset: ; 570 | --tw-ring-offset-width: 0px; 571 | --tw-ring-offset-color: #fff; 572 | --tw-ring-color: rgb(59 130 246 / 0.5); 573 | --tw-ring-offset-shadow: 0 0 #0000; 574 | --tw-ring-shadow: 0 0 #0000; 575 | --tw-shadow: 0 0 #0000; 576 | --tw-shadow-colored: 0 0 #0000; 577 | --tw-blur: ; 578 | --tw-brightness: ; 579 | --tw-contrast: ; 580 | --tw-grayscale: ; 581 | --tw-hue-rotate: ; 582 | --tw-invert: ; 583 | --tw-saturate: ; 584 | --tw-sepia: ; 585 | --tw-drop-shadow: ; 586 | --tw-backdrop-blur: ; 587 | --tw-backdrop-brightness: ; 588 | --tw-backdrop-contrast: ; 589 | --tw-backdrop-grayscale: ; 590 | --tw-backdrop-hue-rotate: ; 591 | --tw-backdrop-invert: ; 592 | --tw-backdrop-opacity: ; 593 | --tw-backdrop-saturate: ; 594 | --tw-backdrop-sepia: ; 595 | } 596 | 597 | .cl-trigger { 598 | display: flex; 599 | height: 3rem; 600 | width: 3rem; 601 | align-items: center; 602 | justify-content: center; 603 | border-radius: 9999px; 604 | --tw-bg-opacity: 1; 605 | background-color: rgb(59 130 246 / var(--tw-bg-opacity)); 606 | font-weight: 700; 607 | --tw-text-opacity: 1; 608 | color: rgb(255 255 255 / var(--tw-text-opacity)); 609 | transition-property: all; 610 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 611 | transition-duration: 150ms; 612 | } 613 | 614 | .cl-trigger:hover { 615 | --tw-bg-opacity: 1; 616 | background-color: rgb(29 78 216 / var(--tw-bg-opacity)); 617 | } 618 | 619 | .cl-window { 620 | display: flex; 621 | flex-direction: column; 622 | overflow: hidden; 623 | border-radius: 1rem; 624 | --tw-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 625 | --tw-shadow-colored: 0 0 10px var(--tw-shadow-color); 626 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 627 | } 628 | 629 | .cl-scale-100 { 630 | --tw-scale-x: 1; 631 | --tw-scale-y: 1; 632 | -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 633 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 634 | } 635 | 636 | .cl-scale-0 { 637 | --tw-scale-x: 0; 638 | --tw-scale-y: 0; 639 | -webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 640 | transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 641 | } 642 | 643 | .cl-trigger-icon { 644 | position: absolute; 645 | height: 50%; 646 | width: 50%; 647 | transition-property: all; 648 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 649 | transition-duration: 500ms; 650 | } 651 | 652 | .cl-chat-window { 653 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 654 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 655 | sans-serif; 656 | position: absolute; 657 | transition-property: all; 658 | transition-duration: 300ms; 659 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 660 | } 661 | 662 | .cl-online-message { 663 | height: 0.5rem; 664 | width: 0.5rem; 665 | border-radius: 9999px; 666 | --tw-bg-opacity: 1; 667 | background-color: rgb(34 197 94 / var(--tw-bg-opacity)); 668 | } 669 | 670 | .cl-offline-message { 671 | height: 0.5rem; 672 | width: 0.5rem; 673 | border-radius: 9999px; 674 | --tw-bg-opacity: 1; 675 | background-color: rgb(239 68 68 / var(--tw-bg-opacity)); 676 | } 677 | 678 | .cl-send-icon { 679 | margin-right: 1.25rem; 680 | height: 1.5rem; 681 | width: 1.5rem; 682 | } 683 | 684 | .cl-notsending-message { 685 | stroke: #3b82f6; 686 | } 687 | 688 | .cl-notsending-message:hover { 689 | stroke: #60a5fa; 690 | } 691 | 692 | .cl-sending-message { 693 | stroke: #9ca3af; 694 | } 695 | 696 | .cl-header-subtitle { 697 | display: flex; 698 | align-items: center; 699 | gap: 0.5rem; 700 | font-size: 0.875rem; 701 | line-height: 1.25rem; 702 | font-weight: 300; 703 | color: rgb(107 114 128); 704 | } 705 | 706 | .cl-header { 707 | z-index: 10; 708 | display: flex; 709 | flex-direction: column; 710 | --tw-bg-opacity: 1; 711 | background-color: rgb(255 255 255 / var(--tw-bg-opacity)); 712 | padding-top: 1rem; 713 | padding-bottom: 1rem; 714 | padding-left: 1.5rem; 715 | padding-right: 1.5rem; 716 | font-size: 1.125rem; 717 | line-height: 1.75rem; 718 | font-weight: 400; 719 | color: rgb(17 24 39); 720 | --tw-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 721 | --tw-shadow-colored: 0 0 10px var(--tw-shadow-color); 722 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 723 | } 724 | 725 | .cl-messages_container { 726 | z-index: 0; 727 | display: flex; 728 | height: 100%; 729 | width: 100%; 730 | flex-direction: column; 731 | overflow: scroll; 732 | overflow-x: clip; 733 | --tw-bg-opacity: 1; 734 | background-color: rgb(249 250 251 / var(--tw-bg-opacity)); 735 | padding-left: 1rem; 736 | padding-right: 1rem; 737 | padding-top: 0.5rem; 738 | padding-bottom: 0.5rem; 739 | -ms-overflow-style: none; 740 | scrollbar-width: none; 741 | } 742 | 743 | .cl-messages_container::-webkit-scrollbar { 744 | display: none; 745 | } 746 | 747 | .cl-input_container { 748 | display: flex; 749 | width: 100%; 750 | align-items: center; 751 | border-top-width: 1px; 752 | --tw-border-opacity: 1; 753 | border-color: rgb(229 231 235 / var(--tw-border-opacity)); 754 | --tw-bg-opacity: 1; 755 | background-color: rgb(255 255 255 / var(--tw-bg-opacity)); 756 | } 757 | 758 | .cl-chat-message { 759 | display: flex; 760 | width: 100%; 761 | padding-top: 0.5rem; 762 | padding-bottom: 0.5rem; 763 | padding-left: 0.5rem; 764 | padding-right: 0.5rem; 765 | } 766 | 767 | @-webkit-keyframes pulse { 768 | 50% { 769 | opacity: .5; 770 | } 771 | } 772 | 773 | @keyframes pulse { 774 | 50% { 775 | opacity: .5; 776 | } 777 | } 778 | 779 | .cl-animate-pulse { 780 | -webkit-animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; 781 | animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; 782 | } 783 | 784 | .cl-justify-start { 785 | justify-content: flex-start; 786 | } 787 | 788 | .cl-justify-end { 789 | justify-content: flex-end; 790 | } 791 | 792 | .cl-input-element { 793 | height: 100%; 794 | width: 100%; 795 | padding-left: 1.25rem; 796 | padding-right: 1.25rem; 797 | padding-top: 1.25rem; 798 | padding-bottom: 1.25rem; 799 | font-weight: 300; 800 | background-color: rgb(255 255 255); 801 | color: rgb(17 24 39); 802 | } 803 | 804 | .cl-input-element:focus { 805 | outline: 2px solid transparent; 806 | outline-offset: 2px; 807 | } 808 | 809 | .cl-user_message { 810 | width: -webkit-fit-content; 811 | width: -moz-fit-content; 812 | width: fit-content; 813 | max-width: 90%; 814 | -webkit-column-break-before: all; 815 | break-before: all; 816 | border-radius: 0.75rem; 817 | border-top-right-radius: 0.125rem; 818 | --tw-bg-opacity: 1; 819 | background-color: rgb(59 130 246 / var(--tw-bg-opacity)); 820 | padding-left: 1rem; 821 | padding-right: 1rem; 822 | padding-top: 0.5rem; 823 | padding-bottom: 0.5rem; 824 | text-align: right; 825 | --tw-text-opacity: 1; 826 | color: rgb(255 255 255 / var(--tw-text-opacity)); 827 | } 828 | 829 | .cl-error_message { 830 | width: -webkit-fit-content; 831 | width: -moz-fit-content; 832 | width: fit-content; 833 | max-width: 90%; 834 | -webkit-column-break-before: all; 835 | break-before: all; 836 | border-radius: 0.75rem; 837 | border-top-left-radius: 0.125rem; 838 | --tw-bg-opacity: 1; 839 | background-color: rgb(248 113 113 / var(--tw-bg-opacity)); 840 | padding-left: 1rem; 841 | padding-right: 1rem; 842 | padding-top: 0.5rem; 843 | padding-bottom: 0.5rem; 844 | text-align: left; 845 | --tw-text-opacity: 1; 846 | color: rgb(255 255 255 / var(--tw-text-opacity)); 847 | } 848 | 849 | .cl-bot_message { 850 | width: -webkit-fit-content; 851 | width: -moz-fit-content; 852 | width: fit-content; 853 | max-width: 90%; 854 | -webkit-column-break-before: all; 855 | break-before: all; 856 | border-radius: 0.75rem; 857 | border-top-left-radius: 0.125rem; 858 | --tw-bg-opacity: 1; 859 | background-color: rgb(229 231 235 / var(--tw-bg-opacity)); 860 | padding-left: 1rem; 861 | padding-right: 1rem; 862 | padding-top: 0.5rem; 863 | padding-bottom: 0.5rem; 864 | text-align: left; 865 | --tw-text-opacity: 1; 866 | color: rgb(31 41 55 / var(--tw-text-opacity)); 867 | } 868 | 869 | .origin-bottom { 870 | -webkit-transform-origin: bottom; 871 | transform-origin: bottom; 872 | } 873 | 874 | .origin-bottom-left { 875 | -webkit-transform-origin: bottom left; 876 | transform-origin: bottom left; 877 | } 878 | 879 | .origin-bottom-right { 880 | -webkit-transform-origin: bottom right; 881 | transform-origin: bottom right; 882 | } 883 | 884 | .origin-center { 885 | -webkit-transform-origin: center; 886 | transform-origin: center; 887 | } 888 | 889 | .origin-top { 890 | -webkit-transform-origin: top; 891 | transform-origin: top; 892 | } 893 | 894 | .origin-top-left { 895 | -webkit-transform-origin: top left; 896 | transform-origin: top left; 897 | } 898 | 899 | .origin-top-right { 900 | -webkit-transform-origin: top right; 901 | transform-origin: top right; 902 | } 903 | 904 | .shadow { 905 | --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); 906 | --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); 907 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 908 | } 909 | input::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 910 | color: rgb(156 163 175); 911 | opacity: 1; /* Firefox */ 912 | } 913 | 914 | input:-ms-input-placeholder { /* Internet Explorer 10-11 */ 915 | color: rgb(156 163 175); 916 | } 917 | 918 | input::-ms-input-placeholder { /* Microsoft Edge */ 919 | color: rgb(156 163 175); 920 | } 921 | `; 922 | 923 | const markdownBody = ` 924 | 925 | .markdown-body { 926 | --base-size-4: 0.25rem; 927 | --base-size-8: 0.5rem; 928 | --base-size-16: 1rem; 929 | --base-text-weight-normal: 400; 930 | --base-text-weight-medium: 500; 931 | --base-text-weight-semibold: 600; 932 | --fontStack-monospace: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; 933 | } 934 | 935 | @media (prefers-color-scheme: dark) { 936 | .markdown-body, 937 | [data-theme="dark"] { 938 | /*dark*/ 939 | color-scheme: dark; 940 | --focus-outlineColor: #1f6feb; 941 | --fgColor-default: #e6edf3; 942 | --fgColor-muted: #8d96a0; 943 | --fgColor-accent: #4493f8; 944 | --fgColor-success: #3fb950; 945 | --fgColor-attention: #d29922; 946 | --fgColor-danger: #f85149; 947 | --fgColor-done: #ab7df8; 948 | --bgColor-default: #0d1117; 949 | --bgColor-muted: #161b22; 950 | --bgColor-neutral-muted: #6e768166; 951 | --bgColor-attention-muted: #bb800926; 952 | --borderColor-default: #30363d; 953 | --borderColor-muted: #30363db3; 954 | --borderColor-neutral-muted: #6e768166; 955 | --borderColor-accent-emphasis: #1f6feb; 956 | --borderColor-success-emphasis: #238636; 957 | --borderColor-attention-emphasis: #9e6a03; 958 | --borderColor-danger-emphasis: #da3633; 959 | --borderColor-done-emphasis: #8957e5; 960 | --color-prettylights-syntax-comment: #8b949e; 961 | --color-prettylights-syntax-constant: #79c0ff; 962 | --color-prettylights-syntax-constant-other-reference-link: #a5d6ff; 963 | --color-prettylights-syntax-entity: #d2a8ff; 964 | --color-prettylights-syntax-storage-modifier-import: #c9d1d9; 965 | --color-prettylights-syntax-entity-tag: #7ee787; 966 | --color-prettylights-syntax-keyword: #ff7b72; 967 | --color-prettylights-syntax-string: #a5d6ff; 968 | --color-prettylights-syntax-variable: #ffa657; 969 | --color-prettylights-syntax-brackethighlighter-unmatched: #f85149; 970 | --color-prettylights-syntax-brackethighlighter-angle: #8b949e; 971 | --color-prettylights-syntax-invalid-illegal-text: #f0f6fc; 972 | --color-prettylights-syntax-invalid-illegal-bg: #8e1519; 973 | --color-prettylights-syntax-carriage-return-text: #f0f6fc; 974 | --color-prettylights-syntax-carriage-return-bg: #b62324; 975 | --color-prettylights-syntax-string-regexp: #7ee787; 976 | --color-prettylights-syntax-markup-list: #f2cc60; 977 | --color-prettylights-syntax-markup-heading: #1f6feb; 978 | --color-prettylights-syntax-markup-italic: #c9d1d9; 979 | --color-prettylights-syntax-markup-bold: #c9d1d9; 980 | --color-prettylights-syntax-markup-deleted-text: #ffdcd7; 981 | --color-prettylights-syntax-markup-deleted-bg: #67060c; 982 | --color-prettylights-syntax-markup-inserted-text: #aff5b4; 983 | --color-prettylights-syntax-markup-inserted-bg: #033a16; 984 | --color-prettylights-syntax-markup-changed-text: #ffdfb6; 985 | --color-prettylights-syntax-markup-changed-bg: #5a1e02; 986 | --color-prettylights-syntax-markup-ignored-text: #c9d1d9; 987 | --color-prettylights-syntax-markup-ignored-bg: #1158c7; 988 | --color-prettylights-syntax-meta-diff-range: #d2a8ff; 989 | --color-prettylights-syntax-sublimelinter-gutter-mark: #484f58; 990 | } 991 | } 992 | 993 | @media (prefers-color-scheme: light) { 994 | .markdown-body, 995 | [data-theme="light"] { 996 | /*light*/ 997 | color-scheme: light; 998 | --focus-outlineColor: #0969da; 999 | --fgColor-default: #1f2328; 1000 | --fgColor-muted: #636c76; 1001 | --fgColor-accent: #0969da; 1002 | --fgColor-success: #1a7f37; 1003 | --fgColor-attention: #9a6700; 1004 | --fgColor-danger: #d1242f; 1005 | --fgColor-done: #8250df; 1006 | --bgColor-default: #ffffff; 1007 | --bgColor-muted: #f6f8fa; 1008 | --bgColor-neutral-muted: #afb8c133; 1009 | --bgColor-attention-muted: #fff8c5; 1010 | --borderColor-default: #d0d7de; 1011 | --borderColor-muted: #d0d7deb3; 1012 | --borderColor-neutral-muted: #afb8c133; 1013 | --borderColor-accent-emphasis: #0969da; 1014 | --borderColor-success-emphasis: #1a7f37; 1015 | --borderColor-attention-emphasis: #bf8700; 1016 | --borderColor-danger-emphasis: #cf222e; 1017 | --borderColor-done-emphasis: #8250df; 1018 | --color-prettylights-syntax-comment: #57606a; 1019 | --color-prettylights-syntax-constant: #0550ae; 1020 | --color-prettylights-syntax-constant-other-reference-link: #0a3069; 1021 | --color-prettylights-syntax-entity: #6639ba; 1022 | --color-prettylights-syntax-storage-modifier-import: #24292f; 1023 | --color-prettylights-syntax-entity-tag: #0550ae; 1024 | --color-prettylights-syntax-keyword: #cf222e; 1025 | --color-prettylights-syntax-string: #0a3069; 1026 | --color-prettylights-syntax-variable: #953800; 1027 | --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; 1028 | --color-prettylights-syntax-brackethighlighter-angle: #57606a; 1029 | --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; 1030 | --color-prettylights-syntax-invalid-illegal-bg: #82071e; 1031 | --color-prettylights-syntax-carriage-return-text: #f6f8fa; 1032 | --color-prettylights-syntax-carriage-return-bg: #cf222e; 1033 | --color-prettylights-syntax-string-regexp: #116329; 1034 | --color-prettylights-syntax-markup-list: #3b2300; 1035 | --color-prettylights-syntax-markup-heading: #0550ae; 1036 | --color-prettylights-syntax-markup-italic: #24292f; 1037 | --color-prettylights-syntax-markup-bold: #24292f; 1038 | --color-prettylights-syntax-markup-deleted-text: #82071e; 1039 | --color-prettylights-syntax-markup-deleted-bg: #ffebe9; 1040 | --color-prettylights-syntax-markup-inserted-text: #116329; 1041 | --color-prettylights-syntax-markup-inserted-bg: #dafbe1; 1042 | --color-prettylights-syntax-markup-changed-text: #953800; 1043 | --color-prettylights-syntax-markup-changed-bg: #ffd8b5; 1044 | --color-prettylights-syntax-markup-ignored-text: #eaeef2; 1045 | --color-prettylights-syntax-markup-ignored-bg: #0550ae; 1046 | --color-prettylights-syntax-meta-diff-range: #8250df; 1047 | --color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f; 1048 | } 1049 | } 1050 | 1051 | .markdown-body { 1052 | -ms-text-size-adjust: 100%; 1053 | -webkit-text-size-adjust: 100%; 1054 | margin: 0; 1055 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; 1056 | font-size: 16px; 1057 | line-height: 1.5; 1058 | word-wrap: break-word; 1059 | scroll-behavior: auto; 1060 | } 1061 | 1062 | .markdown-body .octicon { 1063 | display: inline-block; 1064 | fill: currentColor; 1065 | vertical-align: text-bottom; 1066 | } 1067 | 1068 | .markdown-body h1:hover .anchor .octicon-link:before, 1069 | .markdown-body h2:hover .anchor .octicon-link:before, 1070 | .markdown-body h3:hover .anchor .octicon-link:before, 1071 | .markdown-body h4:hover .anchor .octicon-link:before, 1072 | .markdown-body h5:hover .anchor .octicon-link:before, 1073 | .markdown-body h6:hover .anchor .octicon-link:before { 1074 | width: 16px; 1075 | height: 16px; 1076 | content: ' '; 1077 | display: inline-block; 1078 | background-color: currentColor; 1079 | -webkit-mask-image: url("data:image/svg+xml,"); 1080 | mask-image: url("data:image/svg+xml,"); 1081 | } 1082 | 1083 | .markdown-body details, 1084 | .markdown-body figcaption, 1085 | .markdown-body figure { 1086 | display: block; 1087 | } 1088 | 1089 | .markdown-body summary { 1090 | display: list-item; 1091 | } 1092 | 1093 | .markdown-body [hidden] { 1094 | display: none !important; 1095 | } 1096 | 1097 | .markdown-body a { 1098 | background-color: transparent; 1099 | color: var(--fgColor-accent); 1100 | text-decoration: none; 1101 | } 1102 | 1103 | .markdown-body abbr[title] { 1104 | border-bottom: none; 1105 | -webkit-text-decoration: underline dotted; 1106 | text-decoration: underline dotted; 1107 | } 1108 | 1109 | .markdown-body b, 1110 | .markdown-body strong { 1111 | font-weight: var(--base-text-weight-semibold, 600); 1112 | } 1113 | 1114 | .markdown-body dfn { 1115 | font-style: italic; 1116 | } 1117 | 1118 | .markdown-body h1 { 1119 | margin: .67em 0; 1120 | font-weight: var(--base-text-weight-semibold, 600); 1121 | padding-bottom: .3em; 1122 | font-size: 2em; 1123 | border-bottom: 1px solid var(--borderColor-muted); 1124 | } 1125 | 1126 | .markdown-body mark { 1127 | background-color: var(--bgColor-attention-muted); 1128 | color: var(--fgColor-default); 1129 | } 1130 | 1131 | .markdown-body small { 1132 | font-size: 90%; 1133 | } 1134 | 1135 | .markdown-body sub, 1136 | .markdown-body sup { 1137 | font-size: 75%; 1138 | line-height: 0; 1139 | position: relative; 1140 | vertical-align: baseline; 1141 | } 1142 | 1143 | .markdown-body sub { 1144 | bottom: -0.25em; 1145 | } 1146 | 1147 | .markdown-body sup { 1148 | top: -0.5em; 1149 | } 1150 | 1151 | .markdown-body img { 1152 | border-style: none; 1153 | max-width: 100%; 1154 | box-sizing: content-box; 1155 | } 1156 | 1157 | .markdown-body code, 1158 | .markdown-body kbd, 1159 | .markdown-body pre, 1160 | .markdown-body samp { 1161 | font-family: monospace; 1162 | font-size: 1em; 1163 | } 1164 | 1165 | .markdown-body figure { 1166 | margin: 1em 40px; 1167 | } 1168 | 1169 | .markdown-body hr { 1170 | box-sizing: content-box; 1171 | overflow: hidden; 1172 | background: transparent; 1173 | border-bottom: 1px solid var(--borderColor-muted); 1174 | height: .25em; 1175 | padding: 0; 1176 | margin: 24px 0; 1177 | background-color: var(--borderColor-default); 1178 | border: 0; 1179 | } 1180 | 1181 | .markdown-body input { 1182 | font: inherit; 1183 | margin: 0; 1184 | overflow: visible; 1185 | font-family: inherit; 1186 | font-size: inherit; 1187 | line-height: inherit; 1188 | } 1189 | 1190 | .markdown-body [type=button], 1191 | .markdown-body [type=reset], 1192 | .markdown-body [type=submit] { 1193 | -webkit-appearance: button; 1194 | appearance: button; 1195 | } 1196 | 1197 | .markdown-body [type=checkbox], 1198 | .markdown-body [type=radio] { 1199 | box-sizing: border-box; 1200 | padding: 0; 1201 | } 1202 | 1203 | .markdown-body [type=number]::-webkit-inner-spin-button, 1204 | .markdown-body [type=number]::-webkit-outer-spin-button { 1205 | height: auto; 1206 | } 1207 | 1208 | .markdown-body [type=search]::-webkit-search-cancel-button, 1209 | .markdown-body [type=search]::-webkit-search-decoration { 1210 | -webkit-appearance: none; 1211 | appearance: none; 1212 | } 1213 | 1214 | .markdown-body ::-webkit-input-placeholder { 1215 | color: inherit; 1216 | opacity: .54; 1217 | } 1218 | 1219 | .markdown-body ::-webkit-file-upload-button { 1220 | -webkit-appearance: button; 1221 | appearance: button; 1222 | font: inherit; 1223 | } 1224 | 1225 | .markdown-body a:hover { 1226 | text-decoration: underline; 1227 | } 1228 | 1229 | .markdown-body ::placeholder { 1230 | color: var(--fgColor-muted); 1231 | opacity: 1; 1232 | } 1233 | 1234 | .markdown-body hr::before { 1235 | display: table; 1236 | content: ""; 1237 | } 1238 | 1239 | .markdown-body hr::after { 1240 | display: table; 1241 | clear: both; 1242 | content: ""; 1243 | } 1244 | 1245 | .markdown-body table { 1246 | border-spacing: 0; 1247 | border-collapse: collapse; 1248 | display: block; 1249 | width: max-content; 1250 | max-width: 100%; 1251 | overflow: auto; 1252 | } 1253 | 1254 | .markdown-body td, 1255 | .markdown-body th { 1256 | padding: 0; 1257 | } 1258 | 1259 | .markdown-body details summary { 1260 | cursor: pointer; 1261 | } 1262 | 1263 | .markdown-body details:not([open])>*:not(summary) { 1264 | display: none; 1265 | } 1266 | 1267 | .markdown-body a:focus, 1268 | .markdown-body [role=button]:focus, 1269 | .markdown-body input[type=radio]:focus, 1270 | .markdown-body input[type=checkbox]:focus { 1271 | outline: 2px solid var(--focus-outlineColor); 1272 | outline-offset: -2px; 1273 | box-shadow: none; 1274 | } 1275 | 1276 | .markdown-body a:focus:not(:focus-visible), 1277 | .markdown-body [role=button]:focus:not(:focus-visible), 1278 | .markdown-body input[type=radio]:focus:not(:focus-visible), 1279 | .markdown-body input[type=checkbox]:focus:not(:focus-visible) { 1280 | outline: solid 1px transparent; 1281 | } 1282 | 1283 | .markdown-body a:focus-visible, 1284 | .markdown-body [role=button]:focus-visible, 1285 | .markdown-body input[type=radio]:focus-visible, 1286 | .markdown-body input[type=checkbox]:focus-visible { 1287 | outline: 2px solid var(--focus-outlineColor); 1288 | outline-offset: -2px; 1289 | box-shadow: none; 1290 | } 1291 | 1292 | .markdown-body a:not([class]):focus, 1293 | .markdown-body a:not([class]):focus-visible, 1294 | .markdown-body input[type=radio]:focus, 1295 | .markdown-body input[type=radio]:focus-visible, 1296 | .markdown-body input[type=checkbox]:focus, 1297 | .markdown-body input[type=checkbox]:focus-visible { 1298 | outline-offset: 0; 1299 | } 1300 | 1301 | .markdown-body kbd { 1302 | display: inline-block; 1303 | padding: 3px 5px; 1304 | font: 11px var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace); 1305 | line-height: 10px; 1306 | color: var(--fgColor-default); 1307 | vertical-align: middle; 1308 | background-color: var(--bgColor-muted); 1309 | border: solid 1px var(--borderColor-neutral-muted); 1310 | border-bottom-color: var(--borderColor-neutral-muted); 1311 | border-radius: 6px; 1312 | box-shadow: inset 0 -1px 0 var(--borderColor-neutral-muted); 1313 | } 1314 | 1315 | .markdown-body h1, 1316 | .markdown-body h2, 1317 | .markdown-body h3, 1318 | .markdown-body h4, 1319 | .markdown-body h5, 1320 | .markdown-body h6 { 1321 | margin-top: 24px; 1322 | margin-bottom: 16px; 1323 | font-weight: var(--base-text-weight-semibold, 600); 1324 | line-height: 1.25; 1325 | } 1326 | 1327 | .markdown-body h2 { 1328 | font-weight: var(--base-text-weight-semibold, 600); 1329 | padding-bottom: .3em; 1330 | font-size: 1.5em; 1331 | border-bottom: 1px solid var(--borderColor-muted); 1332 | } 1333 | 1334 | .markdown-body h3 { 1335 | font-weight: var(--base-text-weight-semibold, 600); 1336 | font-size: 1.25em; 1337 | } 1338 | 1339 | .markdown-body h4 { 1340 | font-weight: var(--base-text-weight-semibold, 600); 1341 | font-size: 1em; 1342 | } 1343 | 1344 | .markdown-body h5 { 1345 | font-weight: var(--base-text-weight-semibold, 600); 1346 | font-size: .875em; 1347 | } 1348 | 1349 | .markdown-body h6 { 1350 | font-weight: var(--base-text-weight-semibold, 600); 1351 | font-size: .85em; 1352 | color: var(--fgColor-muted); 1353 | } 1354 | 1355 | .markdown-body p { 1356 | margin-top: 0; 1357 | margin-bottom: 10px; 1358 | } 1359 | 1360 | .markdown-body blockquote { 1361 | margin: 0; 1362 | padding: 0 1em; 1363 | color: var(--fgColor-muted); 1364 | } 1365 | 1366 | .markdown-body ul, 1367 | .markdown-body ol { 1368 | margin-top: 0; 1369 | margin-bottom: 0; 1370 | padding-left: 2em; 1371 | } 1372 | 1373 | .markdown-body ol ol, 1374 | .markdown-body ul ol { 1375 | list-style-type: lower-roman; 1376 | } 1377 | 1378 | .markdown-body ul ul ol, 1379 | .markdown-body ul ol ol, 1380 | .markdown-body ol ul ol, 1381 | .markdown-body ol ol ol { 1382 | list-style-type: lower-alpha; 1383 | } 1384 | 1385 | .markdown-body dd { 1386 | margin-left: 0; 1387 | } 1388 | 1389 | .markdown-body tt, 1390 | .markdown-body code, 1391 | .markdown-body samp { 1392 | font-family: var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace); 1393 | font-size: 12px; 1394 | } 1395 | 1396 | .markdown-body pre { 1397 | margin-top: 0; 1398 | margin-bottom: 0; 1399 | font-family: var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace); 1400 | font-size: 12px; 1401 | word-wrap: normal; 1402 | } 1403 | 1404 | .markdown-body .octicon { 1405 | display: inline-block; 1406 | overflow: visible !important; 1407 | vertical-align: text-bottom; 1408 | fill: currentColor; 1409 | } 1410 | 1411 | .markdown-body input::-webkit-outer-spin-button, 1412 | .markdown-body input::-webkit-inner-spin-button { 1413 | margin: 0; 1414 | -webkit-appearance: none; 1415 | appearance: none; 1416 | } 1417 | 1418 | .markdown-body .mr-2 { 1419 | margin-right: var(--base-size-8, 8px) !important; 1420 | } 1421 | 1422 | .markdown-body::before { 1423 | display: table; 1424 | content: ""; 1425 | } 1426 | 1427 | .markdown-body::after { 1428 | display: table; 1429 | clear: both; 1430 | content: ""; 1431 | } 1432 | 1433 | .markdown-body>*:first-child { 1434 | margin-top: 0 !important; 1435 | } 1436 | 1437 | .markdown-body>*:last-child { 1438 | margin-bottom: 0 !important; 1439 | } 1440 | 1441 | .markdown-body a:not([href]) { 1442 | color: inherit; 1443 | text-decoration: none; 1444 | } 1445 | 1446 | .markdown-body .absent { 1447 | color: var(--fgColor-danger); 1448 | } 1449 | 1450 | .markdown-body .anchor { 1451 | float: left; 1452 | padding-right: 4px; 1453 | margin-left: -20px; 1454 | line-height: 1; 1455 | } 1456 | 1457 | .markdown-body .anchor:focus { 1458 | outline: none; 1459 | } 1460 | 1461 | .markdown-body p, 1462 | .markdown-body blockquote, 1463 | .markdown-body ul, 1464 | .markdown-body ol, 1465 | .markdown-body dl, 1466 | .markdown-body table, 1467 | .markdown-body pre, 1468 | .markdown-body details { 1469 | margin-top: 0; 1470 | margin-bottom: 16px; 1471 | } 1472 | 1473 | .markdown-body blockquote>:first-child { 1474 | margin-top: 0; 1475 | } 1476 | 1477 | .markdown-body blockquote>:last-child { 1478 | margin-bottom: 0; 1479 | } 1480 | 1481 | .markdown-body h1 .octicon-link, 1482 | .markdown-body h2 .octicon-link, 1483 | .markdown-body h3 .octicon-link, 1484 | .markdown-body h4 .octicon-link, 1485 | .markdown-body h5 .octicon-link, 1486 | .markdown-body h6 .octicon-link { 1487 | color: var(--fgColor-default); 1488 | vertical-align: middle; 1489 | visibility: hidden; 1490 | } 1491 | 1492 | .markdown-body h1:hover .anchor, 1493 | .markdown-body h2:hover .anchor, 1494 | .markdown-body h3:hover .anchor, 1495 | .markdown-body h4:hover .anchor, 1496 | .markdown-body h5:hover .anchor, 1497 | .markdown-body h6:hover .anchor { 1498 | text-decoration: none; 1499 | } 1500 | 1501 | .markdown-body h1:hover .anchor .octicon-link, 1502 | .markdown-body h2:hover .anchor .octicon-link, 1503 | .markdown-body h3:hover .anchor .octicon-link, 1504 | .markdown-body h4:hover .anchor .octicon-link, 1505 | .markdown-body h5:hover .anchor .octicon-link, 1506 | .markdown-body h6:hover .anchor .octicon-link { 1507 | visibility: visible; 1508 | } 1509 | 1510 | .markdown-body h1 tt, 1511 | .markdown-body h1 code, 1512 | .markdown-body h2 tt, 1513 | .markdown-body h2 code, 1514 | .markdown-body h3 tt, 1515 | .markdown-body h3 code, 1516 | .markdown-body h4 tt, 1517 | .markdown-body h4 code, 1518 | .markdown-body h5 tt, 1519 | .markdown-body h5 code, 1520 | .markdown-body h6 tt, 1521 | .markdown-body h6 code { 1522 | padding: 0 .2em; 1523 | font-size: inherit; 1524 | } 1525 | 1526 | .markdown-body summary h1, 1527 | .markdown-body summary h2, 1528 | .markdown-body summary h3, 1529 | .markdown-body summary h4, 1530 | .markdown-body summary h5, 1531 | .markdown-body summary h6 { 1532 | display: inline-block; 1533 | } 1534 | 1535 | .markdown-body summary h1 .anchor, 1536 | .markdown-body summary h2 .anchor, 1537 | .markdown-body summary h3 .anchor, 1538 | .markdown-body summary h4 .anchor, 1539 | .markdown-body summary h5 .anchor, 1540 | .markdown-body summary h6 .anchor { 1541 | margin-left: -40px; 1542 | } 1543 | 1544 | .markdown-body summary h1, 1545 | .markdown-body summary h2 { 1546 | padding-bottom: 0; 1547 | border-bottom: 0; 1548 | } 1549 | 1550 | .markdown-body ul.no-list, 1551 | .markdown-body ol.no-list { 1552 | padding: 0; 1553 | list-style-type: none; 1554 | } 1555 | 1556 | .markdown-body ol[type="a s"] { 1557 | list-style-type: lower-alpha; 1558 | } 1559 | 1560 | .markdown-body ol[type="A s"] { 1561 | list-style-type: upper-alpha; 1562 | } 1563 | 1564 | .markdown-body ol[type="i s"] { 1565 | list-style-type: lower-roman; 1566 | } 1567 | 1568 | .markdown-body ol[type="I s"] { 1569 | list-style-type: upper-roman; 1570 | } 1571 | 1572 | .markdown-body ol[type="1"] { 1573 | list-style-type: decimal; 1574 | } 1575 | 1576 | .markdown-body div>ol:not([type]) { 1577 | list-style-type: decimal; 1578 | } 1579 | 1580 | .markdown-body ul ul, 1581 | .markdown-body ul ol, 1582 | .markdown-body ol ol, 1583 | .markdown-body ol ul { 1584 | margin-top: 0; 1585 | margin-bottom: 0; 1586 | } 1587 | 1588 | .markdown-body li>p { 1589 | margin-top: 16px; 1590 | } 1591 | 1592 | .markdown-body li+li { 1593 | margin-top: .25em; 1594 | } 1595 | 1596 | .markdown-body dl { 1597 | padding: 0; 1598 | } 1599 | 1600 | .markdown-body dl dt { 1601 | padding: 0; 1602 | margin-top: 16px; 1603 | font-size: 1em; 1604 | font-style: italic; 1605 | font-weight: var(--base-text-weight-semibold, 600); 1606 | } 1607 | 1608 | .markdown-body dl dd { 1609 | padding: 0 16px; 1610 | margin-bottom: 16px; 1611 | } 1612 | 1613 | .markdown-body table th { 1614 | font-weight: var(--base-text-weight-semibold, 600); 1615 | } 1616 | 1617 | .markdown-body table th, 1618 | .markdown-body table td { 1619 | padding: 6px 13px; 1620 | border: 1px solid var(--borderColor-default); 1621 | } 1622 | 1623 | .markdown-body table td>:last-child { 1624 | margin-bottom: 0; 1625 | } 1626 | 1627 | .markdown-body table tr { 1628 | border-top: 1px solid var(--borderColor-muted); 1629 | } 1630 | 1631 | .markdown-body table img { 1632 | background-color: transparent; 1633 | } 1634 | 1635 | .markdown-body img[align=right] { 1636 | padding-left: 20px; 1637 | } 1638 | 1639 | .markdown-body img[align=left] { 1640 | padding-right: 20px; 1641 | } 1642 | 1643 | .markdown-body .emoji { 1644 | max-width: none; 1645 | vertical-align: text-top; 1646 | background-color: transparent; 1647 | } 1648 | 1649 | .markdown-body span.frame { 1650 | display: block; 1651 | overflow: hidden; 1652 | } 1653 | 1654 | .markdown-body span.frame>span { 1655 | display: block; 1656 | float: left; 1657 | width: auto; 1658 | padding: 7px; 1659 | margin: 13px 0 0; 1660 | overflow: hidden; 1661 | border: 1px solid var(--borderColor-default); 1662 | } 1663 | 1664 | .markdown-body span.frame span img { 1665 | display: block; 1666 | float: left; 1667 | } 1668 | 1669 | .markdown-body span.frame span span { 1670 | display: block; 1671 | padding: 5px 0 0; 1672 | clear: both; 1673 | color: var(--fgColor-default); 1674 | } 1675 | 1676 | .markdown-body span.align-center { 1677 | display: block; 1678 | overflow: hidden; 1679 | clear: both; 1680 | } 1681 | 1682 | .markdown-body span.align-center>span { 1683 | display: block; 1684 | margin: 13px auto 0; 1685 | overflow: hidden; 1686 | text-align: center; 1687 | } 1688 | 1689 | .markdown-body span.align-center span img { 1690 | margin: 0 auto; 1691 | text-align: center; 1692 | } 1693 | 1694 | .markdown-body span.align-right { 1695 | display: block; 1696 | overflow: hidden; 1697 | clear: both; 1698 | } 1699 | 1700 | .markdown-body span.align-right>span { 1701 | display: block; 1702 | margin: 13px 0 0; 1703 | overflow: hidden; 1704 | text-align: right; 1705 | } 1706 | 1707 | .markdown-body span.align-right span img { 1708 | margin: 0; 1709 | text-align: right; 1710 | } 1711 | 1712 | .markdown-body span.float-left { 1713 | display: block; 1714 | float: left; 1715 | margin-right: 13px; 1716 | overflow: hidden; 1717 | } 1718 | 1719 | .markdown-body span.float-left span { 1720 | margin: 13px 0 0; 1721 | } 1722 | 1723 | .markdown-body span.float-right { 1724 | display: block; 1725 | float: right; 1726 | margin-left: 13px; 1727 | overflow: hidden; 1728 | } 1729 | 1730 | .markdown-body span.float-right>span { 1731 | display: block; 1732 | margin: 13px auto 0; 1733 | overflow: hidden; 1734 | text-align: right; 1735 | } 1736 | 1737 | .markdown-body code, 1738 | .markdown-body tt { 1739 | padding: .2em .4em; 1740 | margin: 0; 1741 | font-size: 85%; 1742 | white-space: break-spaces; 1743 | background-color: var(--bgColor-neutral-muted); 1744 | border-radius: 6px; 1745 | } 1746 | 1747 | .markdown-body code br, 1748 | .markdown-body tt br { 1749 | display: none; 1750 | } 1751 | 1752 | .markdown-body del code { 1753 | text-decoration: inherit; 1754 | } 1755 | 1756 | .markdown-body samp { 1757 | font-size: 85%; 1758 | } 1759 | 1760 | .markdown-body pre code { 1761 | font-size: 100%; 1762 | } 1763 | 1764 | .markdown-body pre>code { 1765 | padding: 0; 1766 | margin: 0; 1767 | word-break: normal; 1768 | white-space: pre; 1769 | background: transparent; 1770 | border: 0; 1771 | } 1772 | 1773 | .markdown-body .highlight { 1774 | margin-bottom: 16px; 1775 | } 1776 | 1777 | .markdown-body .highlight pre { 1778 | margin-bottom: 0; 1779 | word-break: normal; 1780 | } 1781 | 1782 | .markdown-body .highlight pre, 1783 | .markdown-body pre { 1784 | padding: 16px; 1785 | overflow: auto; 1786 | font-size: 85%; 1787 | line-height: 1.45; 1788 | color: var(--fgColor-default); 1789 | background-color: var(--bgColor-muted); 1790 | border-radius: 6px; 1791 | } 1792 | 1793 | .markdown-body pre code, 1794 | .markdown-body pre tt { 1795 | display: inline; 1796 | max-width: auto; 1797 | padding: 0; 1798 | margin: 0; 1799 | overflow: visible; 1800 | line-height: inherit; 1801 | word-wrap: normal; 1802 | background-color: transparent; 1803 | border: 0; 1804 | } 1805 | 1806 | .markdown-body .csv-data td, 1807 | .markdown-body .csv-data th { 1808 | padding: 5px; 1809 | overflow: hidden; 1810 | font-size: 12px; 1811 | line-height: 1; 1812 | text-align: left; 1813 | white-space: nowrap; 1814 | } 1815 | 1816 | .markdown-body .csv-data .blob-num { 1817 | padding: 10px 8px 9px; 1818 | text-align: right; 1819 | border: 0; 1820 | } 1821 | 1822 | .markdown-body .csv-data tr { 1823 | border-top: 0; 1824 | } 1825 | 1826 | .markdown-body .csv-data th { 1827 | font-weight: var(--base-text-weight-semibold, 600); 1828 | background: var(--bgColor-muted); 1829 | border-top: 0; 1830 | } 1831 | 1832 | .markdown-body [data-footnote-ref]::before { 1833 | content: "["; 1834 | } 1835 | 1836 | .markdown-body [data-footnote-ref]::after { 1837 | content: "]"; 1838 | } 1839 | 1840 | .markdown-body .footnotes { 1841 | font-size: 12px; 1842 | color: var(--fgColor-muted); 1843 | border-top: 1px solid var(--borderColor-default); 1844 | } 1845 | 1846 | .markdown-body .footnotes ol { 1847 | padding-left: 16px; 1848 | } 1849 | 1850 | .markdown-body .footnotes ol ul { 1851 | display: inline-block; 1852 | padding-left: 16px; 1853 | margin-top: 16px; 1854 | } 1855 | 1856 | .markdown-body .footnotes li { 1857 | position: relative; 1858 | } 1859 | 1860 | .markdown-body .footnotes li:target::before { 1861 | position: absolute; 1862 | top: -8px; 1863 | right: -8px; 1864 | bottom: -8px; 1865 | left: -24px; 1866 | pointer-events: none; 1867 | content: ""; 1868 | border: 2px solid var(--borderColor-accent-emphasis); 1869 | border-radius: 6px; 1870 | } 1871 | 1872 | .markdown-body .footnotes li:target { 1873 | color: var(--fgColor-default); 1874 | } 1875 | 1876 | .markdown-body .footnotes .data-footnote-backref g-emoji { 1877 | font-family: monospace; 1878 | } 1879 | 1880 | .markdown-body .pl-c { 1881 | color: var(--color-prettylights-syntax-comment); 1882 | } 1883 | 1884 | .markdown-body .pl-c1, 1885 | .markdown-body .pl-s .pl-v { 1886 | color: var(--color-prettylights-syntax-constant); 1887 | } 1888 | 1889 | .markdown-body .pl-e, 1890 | .markdown-body .pl-en { 1891 | color: var(--color-prettylights-syntax-entity); 1892 | } 1893 | 1894 | .markdown-body .pl-smi, 1895 | .markdown-body .pl-s .pl-s1 { 1896 | color: var(--color-prettylights-syntax-storage-modifier-import); 1897 | } 1898 | 1899 | .markdown-body .pl-ent { 1900 | color: var(--color-prettylights-syntax-entity-tag); 1901 | } 1902 | 1903 | .markdown-body .pl-k { 1904 | color: var(--color-prettylights-syntax-keyword); 1905 | } 1906 | 1907 | .markdown-body .pl-s, 1908 | .markdown-body .pl-pds, 1909 | .markdown-body .pl-s .pl-pse .pl-s1, 1910 | .markdown-body .pl-sr, 1911 | .markdown-body .pl-sr .pl-cce, 1912 | .markdown-body .pl-sr .pl-sre, 1913 | .markdown-body .pl-sr .pl-sra { 1914 | color: var(--color-prettylights-syntax-string); 1915 | } 1916 | 1917 | .markdown-body .pl-v, 1918 | .markdown-body .pl-smw { 1919 | color: var(--color-prettylights-syntax-variable); 1920 | } 1921 | 1922 | .markdown-body .pl-bu { 1923 | color: var(--color-prettylights-syntax-brackethighlighter-unmatched); 1924 | } 1925 | 1926 | .markdown-body .pl-ii { 1927 | color: var(--color-prettylights-syntax-invalid-illegal-text); 1928 | background-color: var(--color-prettylights-syntax-invalid-illegal-bg); 1929 | } 1930 | 1931 | .markdown-body .pl-c2 { 1932 | color: var(--color-prettylights-syntax-carriage-return-text); 1933 | background-color: var(--color-prettylights-syntax-carriage-return-bg); 1934 | } 1935 | 1936 | .markdown-body .pl-sr .pl-cce { 1937 | font-weight: bold; 1938 | color: var(--color-prettylights-syntax-string-regexp); 1939 | } 1940 | 1941 | .markdown-body .pl-ml { 1942 | color: var(--color-prettylights-syntax-markup-list); 1943 | } 1944 | 1945 | .markdown-body .pl-mh, 1946 | .markdown-body .pl-mh .pl-en, 1947 | .markdown-body .pl-ms { 1948 | font-weight: bold; 1949 | color: var(--color-prettylights-syntax-markup-heading); 1950 | } 1951 | 1952 | .markdown-body .pl-mi { 1953 | font-style: italic; 1954 | color: var(--color-prettylights-syntax-markup-italic); 1955 | } 1956 | 1957 | .markdown-body .pl-mb { 1958 | font-weight: bold; 1959 | color: var(--color-prettylights-syntax-markup-bold); 1960 | } 1961 | 1962 | .markdown-body .pl-md { 1963 | color: var(--color-prettylights-syntax-markup-deleted-text); 1964 | background-color: var(--color-prettylights-syntax-markup-deleted-bg); 1965 | } 1966 | 1967 | .markdown-body .pl-mi1 { 1968 | color: var(--color-prettylights-syntax-markup-inserted-text); 1969 | background-color: var(--color-prettylights-syntax-markup-inserted-bg); 1970 | } 1971 | 1972 | .markdown-body .pl-mc { 1973 | color: var(--color-prettylights-syntax-markup-changed-text); 1974 | background-color: var(--color-prettylights-syntax-markup-changed-bg); 1975 | } 1976 | 1977 | .markdown-body .pl-mi2 { 1978 | color: var(--color-prettylights-syntax-markup-ignored-text); 1979 | background-color: var(--color-prettylights-syntax-markup-ignored-bg); 1980 | } 1981 | 1982 | .markdown-body .pl-mdr { 1983 | font-weight: bold; 1984 | color: var(--color-prettylights-syntax-meta-diff-range); 1985 | } 1986 | 1987 | .markdown-body .pl-ba { 1988 | color: var(--color-prettylights-syntax-brackethighlighter-angle); 1989 | } 1990 | 1991 | .markdown-body .pl-sg { 1992 | color: var(--color-prettylights-syntax-sublimelinter-gutter-mark); 1993 | } 1994 | 1995 | .markdown-body .pl-corl { 1996 | text-decoration: underline; 1997 | color: var(--color-prettylights-syntax-constant-other-reference-link); 1998 | } 1999 | 2000 | .markdown-body [role=button]:focus:not(:focus-visible), 2001 | .markdown-body [role=tabpanel][tabindex="0"]:focus:not(:focus-visible), 2002 | .markdown-body button:focus:not(:focus-visible), 2003 | .markdown-body summary:focus:not(:focus-visible), 2004 | .markdown-body a:focus:not(:focus-visible) { 2005 | outline: none; 2006 | box-shadow: none; 2007 | } 2008 | 2009 | .markdown-body [tabindex="0"]:focus:not(:focus-visible), 2010 | .markdown-body details-dialog:focus:not(:focus-visible) { 2011 | outline: none; 2012 | } 2013 | 2014 | .markdown-body g-emoji { 2015 | display: inline-block; 2016 | min-width: 1ch; 2017 | font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; 2018 | font-size: 1em; 2019 | font-style: normal !important; 2020 | font-weight: var(--base-text-weight-normal, 400); 2021 | line-height: 1; 2022 | vertical-align: -0.075em; 2023 | } 2024 | 2025 | .markdown-body g-emoji img { 2026 | width: 1em; 2027 | height: 1em; 2028 | } 2029 | 2030 | .markdown-body .task-list-item { 2031 | list-style-type: none; 2032 | } 2033 | 2034 | .markdown-body .task-list-item label { 2035 | font-weight: var(--base-text-weight-normal, 400); 2036 | } 2037 | 2038 | .markdown-body .task-list-item.enabled label { 2039 | cursor: pointer; 2040 | } 2041 | 2042 | .markdown-body .task-list-item+.task-list-item { 2043 | margin-top: var(--base-size-4); 2044 | } 2045 | 2046 | .markdown-body .task-list-item .handle { 2047 | display: none; 2048 | } 2049 | 2050 | .markdown-body .task-list-item-checkbox { 2051 | margin: 0 .2em .25em -1.4em; 2052 | vertical-align: middle; 2053 | } 2054 | 2055 | .markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox { 2056 | margin: 0 -1.6em .25em .2em; 2057 | } 2058 | 2059 | .markdown-body .contains-task-list { 2060 | position: relative; 2061 | } 2062 | 2063 | .markdown-body .contains-task-list:hover .task-list-item-convert-container, 2064 | .markdown-body .contains-task-list:focus-within .task-list-item-convert-container { 2065 | display: block; 2066 | width: auto; 2067 | height: 24px; 2068 | overflow: visible; 2069 | clip: auto; 2070 | } 2071 | 2072 | .markdown-body ::-webkit-calendar-picker-indicator { 2073 | filter: invert(50%); 2074 | } 2075 | 2076 | .markdown-body .markdown-alert { 2077 | padding: var(--base-size-8) var(--base-size-16); 2078 | margin-bottom: var(--base-size-16); 2079 | color: inherit; 2080 | border-left: .25em solid var(--borderColor-default); 2081 | } 2082 | 2083 | .markdown-body .markdown-alert>:first-child { 2084 | margin-top: 0; 2085 | } 2086 | 2087 | .markdown-body .markdown-alert>:last-child { 2088 | margin-bottom: 0; 2089 | } 2090 | 2091 | .markdown-body .markdown-alert .markdown-alert-title { 2092 | display: flex; 2093 | font-weight: var(--base-text-weight-medium, 500); 2094 | align-items: center; 2095 | line-height: 1; 2096 | } 2097 | 2098 | .markdown-body .markdown-alert.markdown-alert-note { 2099 | border-left-color: var(--borderColor-accent-emphasis); 2100 | } 2101 | 2102 | .markdown-body .markdown-alert.markdown-alert-note .markdown-alert-title { 2103 | color: var(--fgColor-accent); 2104 | } 2105 | 2106 | .markdown-body .markdown-alert.markdown-alert-important { 2107 | border-left-color: var(--borderColor-done-emphasis); 2108 | } 2109 | 2110 | .markdown-body .markdown-alert.markdown-alert-important .markdown-alert-title { 2111 | color: var(--fgColor-done); 2112 | } 2113 | 2114 | .markdown-body .markdown-alert.markdown-alert-warning { 2115 | border-left-color: var(--borderColor-attention-emphasis); 2116 | } 2117 | 2118 | .markdown-body .markdown-alert.markdown-alert-warning .markdown-alert-title { 2119 | color: var(--fgColor-attention); 2120 | } 2121 | 2122 | .markdown-body .markdown-alert.markdown-alert-tip { 2123 | border-left-color: var(--borderColor-success-emphasis); 2124 | } 2125 | 2126 | .markdown-body .markdown-alert.markdown-alert-tip .markdown-alert-title { 2127 | color: var(--fgColor-success); 2128 | } 2129 | 2130 | .markdown-body .markdown-alert.markdown-alert-caution { 2131 | border-left-color: var(--borderColor-danger-emphasis); 2132 | } 2133 | 2134 | .markdown-body .markdown-alert.markdown-alert-caution .markdown-alert-title { 2135 | color: var(--fgColor-danger); 2136 | } 2137 | 2138 | .markdown-body>*:first-child>.heading-element:first-child { 2139 | margin-top: 0 !important; 2140 | }` 2141 | return ( 2142 |
2143 | 2144 | 2150 | 2183 |
2184 | ); 2185 | } 2186 | -------------------------------------------------------------------------------- /src/chatWidget/utils.ts: -------------------------------------------------------------------------------- 1 | export function getChatPosition( 2 | triggerPosition: DOMRect, 3 | Cwidth:number, 4 | Cheight:number, 5 | position?: string, 6 | ): { top: string; left: string; 7 | position?: string, } { 8 | if (!triggerPosition) { 9 | return { top: "0px", left: "0px" }; // Return empty string if trigger position is not available 10 | } 11 | 12 | const { top, left, width, height } = triggerPosition; 13 | 14 | const distance = 5; // Adjust this value to set the desired distance from the trigger 15 | if(!position) return { top: distance + height+ "px", left: width + "px" }; 16 | 17 | switch (position) { 18 | case "top-left": 19 | return { top: - distance - Cheight + "px", left: -Cwidth + "px" }; 20 | case "top-center": 21 | return { top: - distance - Cheight + "px", left: width/2-Cwidth / 2 + "px" }; 22 | case "top-right": 23 | return { top: - distance - Cheight + "px", left: width+ "px" }; 24 | case "center-left": 25 | return { top: width/2-Cheight/2 + "px", left: -Cwidth - distance + "px" }; 26 | case "center-right": 27 | return { 28 | top: width/2-Cheight/2 + "px", 29 | left: width + distance + "px", 30 | }; 31 | case "bottom-right": 32 | return { top: distance + height+ "px", left: width + "px" }; 33 | case "bottom-center": 34 | return { 35 | top: distance + height+ "px", 36 | left: width/2-Cwidth / 2 + "px", 37 | }; 38 | case "bottom-left": 39 | return { top: distance + height+ "px", left: -Cwidth + "px"}; 40 | default: 41 | return { top: distance + height+ "px", left: width + "px" }; 42 | } 43 | } 44 | 45 | export function getAnimationOrigin(position?:string) { 46 | if(!position) return "origin-top-left"; 47 | switch (position) { 48 | case "top-left": 49 | return 'origin-bottom-right' 50 | case "top-center": 51 | return "origin-bottom"; 52 | case "top-right": 53 | return "origin-bottom-left"; 54 | case "center-left": 55 | return "origin-center"; 56 | case "center-right": 57 | return "origin-center"; 58 | case "bottom-right": 59 | return "origin-top-left"; 60 | case "bottom-center": 61 | return "origin-top"; 62 | case "bottom-left": 63 | return "origin-top-right" 64 | default: 65 | return "origin-top-left" 66 | } 67 | } 68 | 69 | export function extractMessageFromOutput(output:{type:string, message:any}){ 70 | console.log(output) 71 | const {type, message} = output; 72 | if(type === "text") return message; 73 | if (type ==="message") return message.text; 74 | if(type==="object") return message.text; 75 | return "Unknown message structure" 76 | } -------------------------------------------------------------------------------- /src/controllers/index.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export async function sendMessage(baseUrl: string, flowId: string, message: string,input_type:string,output_type:string,sessionId:React.MutableRefObject,output_component?:string, tweaks?: Object,api_key?:string,additional_headers?:{[key:string]:string}) { 4 | let data:any; 5 | data = {input_type,input_value:message,output_type} 6 | if (tweaks) { 7 | data["tweaks"]= tweaks 8 | } 9 | if(output_component){ 10 | data["output_component"]=output_component; 11 | } 12 | let headers:{[key:string]:string}= {"Content-Type": "application/json"} 13 | if( api_key){ 14 | headers["x-api-key"]=api_key; 15 | } 16 | if (additional_headers){ 17 | headers = Object.assign(headers, additional_headers); 18 | // headers = {...headers, ...additional_headers}; 19 | } 20 | if(sessionId.current && sessionId.current!=""){ 21 | data.session_id=sessionId.current; 22 | } 23 | let response = axios.post(`${baseUrl}/api/v1/run/${flowId}`, data,{headers}); 24 | return response; 25 | } -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import r2wc from '@r2wc/react-to-web-component'; 2 | import ChatWidget from './chatWidget'; 3 | 4 | customElements.define('langflow-chat', r2wc(ChatWidget, { 5 | shadow: "closed", 6 | props: { 7 | start_open: "boolean", 8 | api_key: "string", 9 | output_type: "string", 10 | input_type: "string", 11 | output_component: "string", 12 | chat_trigger_style: "json", 13 | host_url: "string", 14 | flow_id: "string", 15 | online: "boolean", 16 | online_message: "string", 17 | window_title: "string", 18 | tweaks:"json", 19 | bot_message_style:"json", 20 | user_message_style:"json", 21 | chat_window_style:"json", 22 | height:"number", 23 | width:"number", 24 | session_id:"string", 25 | chat_output_key:"string", 26 | error_message_style:"json", 27 | send_button_style:"json", 28 | send_icon_style:"json", 29 | placeholder:"string", 30 | placeholder_sending:"string", 31 | input_style:"json", 32 | input_container_style:"json", 33 | chat_position:"string", 34 | additional_headers:"json", 35 | }, 36 | })); -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/types/chatWidget/index.ts: -------------------------------------------------------------------------------- 1 | export type ChatMessageType = { 2 | message: string; 3 | isSend: boolean; 4 | error?: boolean; 5 | bot_message_style?: React.CSSProperties; 6 | user_message_style?: React.CSSProperties; 7 | error_message_style?: React.CSSProperties; 8 | }; 9 | 10 | 11 | export type ChatMessagePlaceholderType = { 12 | bot_message_style?: React.CSSProperties; 13 | }; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); 3 | const glob = require("glob"); 4 | 5 | module.exports = { 6 | entry: { 7 | "bundle.js": glob 8 | .sync("build/static/?(js|css)/main.*.?(js|css)") 9 | .map((f) => path.resolve(__dirname, f)), 10 | }, 11 | output: { 12 | filename: "build/static/js/bundle.min.js", 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.css$/, 18 | use: ["style-loader", "css-loader"], 19 | }, 20 | ], 21 | }, 22 | plugins: [ 23 | new UglifyJsPlugin(), 24 | ], 25 | }; 26 | --------------------------------------------------------------------------------