mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-06 19:18:22 +01:00
messages component
This commit is contained in:
parent
2486804d62
commit
2fc9c54785
51
frontend/app/element/chatmessages.less
Normal file
51
frontend/app/element/chatmessages.less
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
.chat-messages {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-message {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-user-icon {
|
||||||
|
height: 1em; /* Make user icon height match the text height */
|
||||||
|
width: 1em; /* Keep the icon proportional */
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-username {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 4px;
|
||||||
|
line-height: 1.4; /* Ensure alignment with the first line of the message */
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-text img {
|
||||||
|
height: 1em; /* Make inline images (rendered via markdown) match the text height */
|
||||||
|
width: auto; /* Keep the aspect ratio of images */
|
||||||
|
margin: 0 4px;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-emoji {
|
||||||
|
margin: 0 2px;
|
||||||
|
font-size: 1em; /* Match emoji size with the text height */
|
||||||
|
}
|
90
frontend/app/element/chatmessages.stories.tsx
Normal file
90
frontend/app/element/chatmessages.stories.tsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
import { ChatMessages } from "./chatmessages";
|
||||||
|
import "./chatmessages.less";
|
||||||
|
|
||||||
|
export interface ChatMessage {
|
||||||
|
id: string;
|
||||||
|
username: string;
|
||||||
|
message: string;
|
||||||
|
color?: string;
|
||||||
|
userIcon?: string;
|
||||||
|
messageIcon?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: "Elements/ChatMessages",
|
||||||
|
component: ChatMessages,
|
||||||
|
args: {
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
username: "User1",
|
||||||
|
message: "Hello everyone! 👋",
|
||||||
|
color: "#ff4500",
|
||||||
|
userIcon: "https://via.placeholder.com/50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
username: "User2",
|
||||||
|
message: "Check this out: ![cool icon](https://via.placeholder.com/20)",
|
||||||
|
color: "#1e90ff",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
username: "User3",
|
||||||
|
message: "This is a simple text message without icons.",
|
||||||
|
color: "#32cd32",
|
||||||
|
userIcon: "https://via.placeholder.com/50",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "4",
|
||||||
|
username: "User4",
|
||||||
|
message: "🎉 👏 Great job!",
|
||||||
|
color: "#ff6347",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "5",
|
||||||
|
username: "User5",
|
||||||
|
message: "Look at this cool icon: Isn't it awesome? ![cool icon](https://via.placeholder.com/20)",
|
||||||
|
color: "#8a2be2",
|
||||||
|
userIcon: "https://via.placeholder.com/50",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
messages: {
|
||||||
|
description: "Array of chat messages to be displayed",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies Meta<typeof ChatMessages>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
|
export const Messages: Story = {
|
||||||
|
render: (args) => (
|
||||||
|
<div>
|
||||||
|
<ChatMessages {...args} />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ScrollableMessages: Story = {
|
||||||
|
render: (args) => (
|
||||||
|
<div style={{ height: "100%", overflow: "hidden" }}>
|
||||||
|
<ChatMessages {...args} />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
args: {
|
||||||
|
messages: Array.from({ length: 50 }, (_, i) => ({
|
||||||
|
id: `${i + 1}`,
|
||||||
|
username: `User${i + 1}`,
|
||||||
|
message: `This is message number ${i + 1}.`,
|
||||||
|
color: i % 2 === 0 ? "#ff6347" : "#1e90ff",
|
||||||
|
userIcon: "https://via.placeholder.com/50",
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
};
|
60
frontend/app/element/chatmessages.tsx
Normal file
60
frontend/app/element/chatmessages.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import { Markdown } from "@/app/element/markdown";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
||||||
|
import { memo, useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
import "./chatmessages.less";
|
||||||
|
|
||||||
|
export interface ChatMessage {
|
||||||
|
id: string;
|
||||||
|
username: string;
|
||||||
|
message: string;
|
||||||
|
color?: string;
|
||||||
|
userIcon?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChatMessagesProps {
|
||||||
|
messages: ChatMessage[];
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChatMessages = memo(({ messages, className }: ChatMessagesProps) => {
|
||||||
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
const overlayScrollRef = useRef(null);
|
||||||
|
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverlayScrollbarsComponent
|
||||||
|
ref={overlayScrollRef}
|
||||||
|
className={clsx("chat-messages", className)}
|
||||||
|
options={{ scrollbars: { autoHide: "leave" } }}
|
||||||
|
>
|
||||||
|
{messages.map(({ id, username, message, color, userIcon }) => (
|
||||||
|
<div key={id} className="chat-message">
|
||||||
|
{userIcon && <img src={userIcon} alt="user icon" className="chat-user-icon" />}
|
||||||
|
<span className="chat-username" style={{ color: color || "var(--main-text-color)" }}>
|
||||||
|
{username}:
|
||||||
|
</span>
|
||||||
|
<span className="chat-text">
|
||||||
|
<Markdown scrollable={false} text={message}></Markdown>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div ref={messagesEndRef} />
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ChatMessages.displayName = "ChatMessages";
|
||||||
|
|
||||||
|
export { ChatMessages };
|
Loading…
Reference in New Issue
Block a user