Skip to content

Commit 1206216

Browse files
committed
Add custom styles for the chatbox component
1 parent c2daad6 commit 1206216

10 files changed

Lines changed: 403 additions & 61 deletions

File tree

client/packages/lowcoder/src/comps/comps/chatBoxComponentv2/ChatBoxContext.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { createContext, useContext } from "react";
22
import type { ChatRoom, OnlineUser, PendingRoomInvite } from "./store";
3+
import type {
4+
ChatBoxV2ContainerStyleType,
5+
ChatBoxV2SidebarStyleType,
6+
ChatBoxV2HeaderStyleType,
7+
ChatBoxV2MessageStyleType,
8+
ChatBoxV2InputStyleType,
9+
AnimationStyleType,
10+
} from "comps/controls/styleControlConstants";
311

412
type ChatEventName =
513
| "messageSent"
@@ -42,8 +50,12 @@ export interface ChatBoxContextValue {
4250
roomsPanelWidth: string;
4351
allowRoomCreation: boolean;
4452
allowRoomSearch: boolean;
45-
style: any;
46-
animationStyle: any;
53+
style: ChatBoxV2ContainerStyleType;
54+
animationStyle: AnimationStyleType;
55+
sidebarStyle: ChatBoxV2SidebarStyleType;
56+
headerStyle: ChatBoxV2HeaderStyleType;
57+
messageStyle: ChatBoxV2MessageStyleType;
58+
inputStyle: ChatBoxV2InputStyleType;
4759

4860
// Events
4961
onEvent: (event: ChatEventName) => any;

client/packages/lowcoder/src/comps/comps/chatBoxComponentv2/chatBoxComp.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import { eventHandlerControl } from "comps/controls/eventHandlerControl";
1414
import { styleControl } from "comps/controls/styleControl";
1515
import {
1616
AnimationStyle,
17-
TextStyle,
17+
ChatBoxV2ContainerStyle,
18+
ChatBoxV2SidebarStyle,
19+
ChatBoxV2HeaderStyle,
20+
ChatBoxV2MessageStyle,
21+
ChatBoxV2InputStyle,
1822
} from "comps/controls/styleControlConstants";
1923
import { hiddenPropertyView } from "comps/utils/propertyUtils";
2024
import { EditorContext } from "comps/editorState";
@@ -124,8 +128,12 @@ const childrenMap = {
124128
// ── Style / layout ────────────────────────────────────────────────
125129
autoHeight: AutoHeightControl,
126130
onEvent: eventHandlerControl(ChatEvents),
127-
style: styleControl(TextStyle, "style"),
131+
style: styleControl(ChatBoxV2ContainerStyle, "style"),
128132
animationStyle: styleControl(AnimationStyle, "animationStyle"),
133+
sidebarStyle: styleControl(ChatBoxV2SidebarStyle, "sidebarStyle"),
134+
headerStyle: styleControl(ChatBoxV2HeaderStyle, "headerStyle"),
135+
messageStyle: styleControl(ChatBoxV2MessageStyle, "messageStyle"),
136+
inputStyle: styleControl(ChatBoxV2InputStyle, "inputStyle"),
129137
};
130138

131139
// ─── Property panel ──────────────────────────────────────────────────────────
@@ -219,6 +227,18 @@ const ChatBoxPropertyView = React.memo((props: { children: any }) => {
219227
<Section name={sectionNames.style}>
220228
{children.style.getPropertyView()}
221229
</Section>
230+
<Section name="Sidebar Style">
231+
{children.sidebarStyle.getPropertyView()}
232+
</Section>
233+
<Section name="Header Style">
234+
{children.headerStyle.getPropertyView()}
235+
</Section>
236+
<Section name="Message Style">
237+
{children.messageStyle.getPropertyView()}
238+
</Section>
239+
<Section name="Input Style">
240+
{children.inputStyle.getPropertyView()}
241+
</Section>
222242
<Section name={sectionNames.animationStyle} hasTooltip={true}>
223243
{children.animationStyle.getPropertyView()}
224244
</Section>
@@ -239,6 +259,8 @@ let ChatBoxV2Tmp = (function () {
239259
const typingUsers = Array.isArray(props.typingUsers) ? props.typingUsers : [];
240260
const onlineUsers = Array.isArray(props.onlineUsers) ? props.onlineUsers : [];
241261
const isAiThinking = Boolean(props.isAiThinking);
262+
// DEBUG: Log onlineUsers to verify data flow from ChatController
263+
console.log("[ChatBox] onlineUsers prop:", onlineUsers.length, onlineUsers.map((u: any) => u.userId));
242264
const pendingInvites = (Array.isArray(props.pendingInvites)
243265
? props.pendingInvites
244266
: []) as unknown as PendingRoomInvite[];
@@ -267,6 +289,10 @@ let ChatBoxV2Tmp = (function () {
267289
allowRoomSearch: props.allowRoomSearch,
268290
style: props.style,
269291
animationStyle: props.animationStyle,
292+
sidebarStyle: props.sidebarStyle,
293+
headerStyle: props.headerStyle,
294+
messageStyle: props.messageStyle,
295+
inputStyle: props.inputStyle,
270296

271297
onEvent: props.onEvent,
272298

client/packages/lowcoder/src/comps/comps/chatBoxComponentv2/components/ChatBoxView.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,11 @@ export const ChatBoxView = React.memo(() => {
2323
? ctx.currentRoom.name
2424
: ctx.chatTitle.value;
2525

26-
// Count users online in the current room (peers only, not counting self)
2726
const roomOnlineCount = useMemo(() => {
2827
if (!ctx.currentRoomId) return 0;
2928
return ctx.onlineUsers.filter(
3029
(u) => u.currentRoomId === ctx.currentRoomId && u.userId !== ctx.currentUserId,
31-
).length + 1; // +1 for self
30+
).length + 1;
3231
}, [ctx.onlineUsers, ctx.currentRoomId, ctx.currentUserId]);
3332

3433
return (
@@ -48,7 +47,7 @@ export const ChatBoxView = React.memo(() => {
4847
{/* ── Chat area ───────────────────────────────────────────── */}
4948
<ChatPanelContainer>
5049
{ctx.showHeader && (
51-
<ChatHeaderBar>
50+
<ChatHeaderBar $headerStyle={ctx.headerStyle}>
5251
<div>
5352
<div style={{ fontWeight: 600, fontSize: 16 }}>
5453
{headerTitle}
@@ -73,6 +72,7 @@ export const ChatBoxView = React.memo(() => {
7372
typingUsers={ctx.typingUsers}
7473
currentUserId={ctx.currentUserId}
7574
isAiThinking={ctx.isAiThinking}
75+
messageStyle={ctx.messageStyle}
7676
/>
7777

7878
<InputBar
@@ -83,6 +83,7 @@ export const ChatBoxView = React.memo(() => {
8383
onStartTyping={() => ctx.onEvent("startTyping")}
8484
onStopTyping={() => ctx.onEvent("stopTyping")}
8585
onDraftChange={(text) => ctx.messageText.onChange(text)}
86+
inputStyle={ctx.inputStyle}
8687
/>
8788
</ChatPanelContainer>
8889

client/packages/lowcoder/src/comps/comps/chatBoxComponentv2/components/InputBar.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import React, { useCallback, useRef, useState } from "react";
22
import { Button } from "antd";
33
import { SendOutlined } from "@ant-design/icons";
4+
import type { ChatBoxV2InputStyleType } from "comps/controls/styleControlConstants";
45
import { InputBarContainer, StyledTextArea } from "../styles";
56

67
export interface InputBarProps {
78
onSend: (text: string) => void;
89
onStartTyping: () => void;
910
onStopTyping: () => void;
1011
onDraftChange: (text: string) => void;
12+
inputStyle?: ChatBoxV2InputStyleType;
1113
}
1214

1315
export const InputBar = React.memo((props: InputBarProps) => {
14-
const { onSend, onStartTyping, onStopTyping, onDraftChange } = props;
16+
const { onSend, onStartTyping, onStopTyping, onDraftChange, inputStyle } = props;
1517
const [draft, setDraft] = useState("");
1618
const typingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
1719
const isTypingRef = useRef(false);
@@ -73,9 +75,16 @@ export const InputBar = React.memo((props: InputBarProps) => {
7375
[onStartTyping, handleStopTyping, clearTypingTimeout, onDraftChange],
7476
);
7577

78+
const sendBtnStyle: React.CSSProperties = inputStyle ? {
79+
backgroundColor: inputStyle.sendButtonBackground,
80+
borderColor: inputStyle.sendButtonBackground,
81+
color: inputStyle.sendButtonIcon,
82+
} : {};
83+
7684
return (
77-
<InputBarContainer>
85+
<InputBarContainer $inputStyle={inputStyle}>
7886
<StyledTextArea
87+
$inputStyle={inputStyle}
7988
value={draft}
8089
onChange={handleInputChange}
8190
onKeyDown={handleKeyDown}
@@ -88,6 +97,7 @@ export const InputBar = React.memo((props: InputBarProps) => {
8897
icon={<SendOutlined />}
8998
onClick={handleSend}
9099
disabled={!draft.trim()}
100+
style={sendBtnStyle}
91101
/>
92102
</InputBarContainer>
93103
);

client/packages/lowcoder/src/comps/comps/chatBoxComponentv2/components/MessageList.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { CopyOutlined, CheckOutlined, RobotOutlined } from "@ant-design/icons";
66
import dayjs from "dayjs";
77
import { parseMessageTimestamp, formatChatTime } from "util/dateTimeUtils";
88
import { LLM_BOT_AUTHOR_ID } from "../store";
9+
import type { ChatBoxV2MessageStyleType } from "comps/controls/styleControlConstants";
910
import {
1011
MessagesArea,
1112
MessageWrapper,
@@ -86,10 +87,11 @@ export interface MessageListProps {
8687
typingUsers: any[];
8788
currentUserId: string;
8889
isAiThinking?: boolean;
90+
messageStyle?: ChatBoxV2MessageStyleType;
8991
}
9092

9193
export const MessageList = React.memo((props: MessageListProps) => {
92-
const { messages, typingUsers, currentUserId, isAiThinking = false } = props;
94+
const { messages, typingUsers, currentUserId, isAiThinking = false, messageStyle } = props;
9395
const containerRef = useRef<HTMLDivElement>(null);
9496

9597
useEffect(() => {
@@ -102,7 +104,7 @@ export const MessageList = React.memo((props: MessageListProps) => {
102104
}, [messages.length, isAiThinking]);
103105

104106
return (
105-
<MessagesArea ref={containerRef}>
107+
<MessagesArea ref={containerRef} $messageStyle={messageStyle}>
106108
{messages.length === 0 ? (
107109
<EmptyChat>
108110
<div style={{ fontSize: 24 }}>💬</div>
@@ -149,10 +151,10 @@ export const MessageList = React.memo((props: MessageListProps) => {
149151

150152
return (
151153
<MessageWrapper key={id} $own={isOwn}>
152-
<BubbleMeta $own={isOwn}>{authorName}</BubbleMeta>
153-
<Bubble $own={isOwn}>{text}</Bubble>
154+
<BubbleMeta $own={isOwn} $messageStyle={messageStyle}>{authorName}</BubbleMeta>
155+
<Bubble $own={isOwn} $messageStyle={messageStyle}>{text}</Bubble>
154156
{ts && (
155-
<BubbleTime $own={isOwn}>
157+
<BubbleTime $own={isOwn} $messageStyle={messageStyle}>
156158
{formatChatTime(ts)}
157159
</BubbleTime>
158160
)}
@@ -161,7 +163,6 @@ export const MessageList = React.memo((props: MessageListProps) => {
161163
})
162164
)}
163165

164-
{/* AI thinking animation — shown to all users when the LLM is generating */}
165166
{isAiThinking && (
166167
<AiBubbleWrapper>
167168
<AiBadge>

client/packages/lowcoder/src/comps/comps/chatBoxComponentv2/components/RoomPanel.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const RoomPanel = React.memo((props: RoomPanelProps) => {
4545
roomsPanelWidth,
4646
pendingInvites,
4747
onlineUsers,
48+
sidebarStyle,
4849
onRoomSwitch,
4950
onRoomJoin,
5051
onRoomLeave,
@@ -108,6 +109,7 @@ export const RoomPanel = React.memo((props: RoomPanelProps) => {
108109
<RoomItemStyled
109110
key={room.id}
110111
$active={isActive}
112+
$sidebarStyle={sidebarStyle}
111113
onClick={() => {
112114
if (isSearch) {
113115
handleJoinAndClear(room.id);
@@ -175,8 +177,8 @@ export const RoomPanel = React.memo((props: RoomPanelProps) => {
175177
};
176178

177179
return (
178-
<RoomPanelContainer $width={roomsPanelWidth}>
179-
<RoomPanelHeader>
180+
<RoomPanelContainer $width={roomsPanelWidth} $sidebarStyle={sidebarStyle}>
181+
<RoomPanelHeader $sidebarStyle={sidebarStyle}>
180182
<span>Rooms</span>
181183
<div style={{ display: "flex", gap: 2 }}>
182184
{onInviteModalOpen && (

0 commit comments

Comments
 (0)