From: Jaehyung Date: Wed, 1 Oct 2025 09:10:17 +0000 (+0000) Subject: Chatbot UI design (without connecting with the backend) X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=cd9e6d65c0dd25800a00ac64b418f362a55153fd;p=portal%2Faiml-dashboard.git Chatbot UI design (without connecting with the backend) - Message bubbles, autoscroll - Support dark/light mode - mounted globally in HomePage - Toggle Chatbot - Connection with the backend will be done soon. Commited to check if the design appears correctly. Issue-ID: AIMLFW-270 Change-Id: If74ed76d9e2464179ddfe334795b5339fa00f788 Signed-off-by: Jaehyung Choi --- diff --git a/src/components/chatbot/Chatbot.js b/src/components/chatbot/Chatbot.js new file mode 100644 index 0000000..6014ee9 --- /dev/null +++ b/src/components/chatbot/Chatbot.js @@ -0,0 +1,117 @@ +import React, { useEffect, useRef, useState } from 'react'; +import './chatbot.css'; + +export function ChatbotToggle() { + const [theme, setTheme] = useState(() => (typeof document !== 'undefined' ? (document.body.getAttribute('data-bs-theme') || 'light') : 'light')); + const [open, setOpen] = useState(false); + const [hoverSend, setHoverSend] = useState(false); + const [hoverFab, setHoverFab] = useState(false); + const [text, setText] = useState(''); + const [messages, setMessages] = useState([ + { id: 1, role: 'assistant', content: 'Hello! How can I assist you today?' } + ]); + const endRef = useRef(null); + + useEffect(() => { + if (endRef.current) { + endRef.current.scrollIntoView({ behavior: 'smooth' }); + } + }, [messages, open]); + + function pushMessage(role, content) { + setMessages((prev) => [...prev, { id: prev.length + 1, role, content }]); + } + + function onKeyDown(e) { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + onSend(); + } + } + + function onSend(e) { + if (e) e.preventDefault(); + if (!text.trim()) return; + const userText = text.trim(); + setText(''); + pushMessage('user', userText); + pushMessage('assistant', 'LLM endpoint is not connected.'); + } + + useEffect(() => { + const body = document.body; + const observer = new MutationObserver((mutations) => { + for (const m of mutations) { + if (m.attributeName === 'data-bs-theme') { + setTheme(body.getAttribute('data-bs-theme') || 'light'); + } + } + }); + observer.observe(body, { attributes: true }); + const onStorage = (e) => { + if (e.key === 'theme') { + setTheme(e.newValue || 'light'); + } + }; + window.addEventListener('storage', onStorage); + return () => { + observer.disconnect(); + window.removeEventListener('storage', onStorage); + }; + }, []); + + const isDark = theme === 'dark'; + + const textColor = isDark ? '#f8fafc' : '#0f172a'; + + return ( + <> + {open && ( +
+
+
+
+ Assistant +
+ +
+ +
+ {messages.map((m) => ( +
+
{m.content}
+
+ ))} +
+
+ +
+