style channels

This commit is contained in:
Red Adaya 2024-10-09 20:44:36 +08:00
parent fa0c2791c5
commit a8e2e0fde6
15 changed files with 424 additions and 336 deletions

View File

@ -16,6 +16,7 @@ import {
import * as WOS from "@/store/wos";
import { focusedBlockId, getElemAsStr } from "@/util/focusutil";
import * as util from "@/util/util";
import { Chat, ChatModel, makeChatModel } from "@/view/chat/chat";
import { CpuPlotView, CpuPlotViewModel, makeCpuPlotViewModel } from "@/view/cpuplot/cpuplot";
import { HelpView, HelpViewModel, makeHelpViewModel } from "@/view/helpview/helpview";
import { TermViewModel, TerminalView, makeTerminalModel } from "@/view/term/term";
@ -53,6 +54,9 @@ function makeViewModel(blockId: string, blockView: string, nodeModel: NodeModel)
if (blockView === "help") {
return makeHelpViewModel();
}
if (blockView === "chat") {
return makeChatModel(blockId);
}
return makeDefaultViewModel(blockId, blockView);
}
@ -98,6 +102,9 @@ function getViewElem(
if (blockView == "tips") {
return <QuickTipsView key={blockId} model={viewModel as QuickTipsViewModel} />;
}
if (blockView == "chat") {
return <Chat key={blockId} model={viewModel as ChatModel} />;
}
return <CenteredDiv>Invalid View "{blockView}"</CenteredDiv>;
}

View File

@ -1,7 +1,7 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
@import "@/app/mixins.less";
@import "../mixins.less";
.button {
// override default button appearance

View File

@ -7,7 +7,7 @@ import "./menu.less";
export interface MenuItem {
text: string;
icon?: React.ReactNode;
icon?: string | React.ReactNode;
children?: MenuItem[];
onClick?: () => void;
}
@ -37,13 +37,18 @@ const Menu = memo(({ items, className, renderItem }: MenuProps) => {
const hasChildren = item.children && item.children.length > 0;
return (
<li key={itemKey} className={clsx("menu-item", className)}>
<li key={itemKey} className="menu-item">
{renderItem ? (
renderItem(item, isOpen, () => handleClick(item, itemKey))
) : (
<div className="menu-item-button" onClick={() => handleClick(item, itemKey)}>
<div className="menu-item-content">
<div className="menu-item-icon">{item.icon}</div>
<div
className={clsx("menu-item-content", {
"has-children": hasChildren,
"is-open": isOpen && hasChildren,
})}
>
{item.icon && <div className="menu-item-icon">{item.icon}</div>}
<div className="menu-item-text">{item.text}</div>
</div>
{hasChildren && (
@ -62,7 +67,11 @@ const Menu = memo(({ items, className, renderItem }: MenuProps) => {
);
};
return <ul className="menu">{items.map((item, index) => renderListItem(item, index, "root"))}</ul>;
return (
<ul className={clsx("menu", className)} role="menu">
{items.map((item, index) => renderListItem(item, index, "root"))}
</ul>
);
});
Menu.displayName = "Menu";

View File

@ -0,0 +1,30 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
.channel-list {
width: 180px;
background-color: rgba(255, 255, 255, 0.025);
overflow-x: hidden;
padding: 5px;
.menu-item-button {
padding: 5px 7px;
}
.nested-list {
padding-left: 10px;
}
.menu-item-text {
color: rgb(from var(--main-text-color) r g b / 0.7);
}
.has-children .menu-item-text {
font-weight: bold;
font-size: 14px;
}
.is-open .menu-item-text {
color: var(--main-text-color);
}
}

View File

@ -0,0 +1,11 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { Menu, MenuItem } from "@/app/element/menu";
import "./channels.less";
const Channels = ({ channels }: { channels: MenuItem[] }) => {
return <Menu className="channel-list" items={channels}></Menu>;
};
export { Channels };

View File

@ -0,0 +1,13 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
.chat-view {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
.chat-section {
flex-grow: 1;
}
}

View File

@ -0,0 +1,48 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { ChatMessage, ChatMessages } from "@/app/element/chatmessages";
import { MenuItem } from "@/app/element/menu";
import { UserStatus } from "@/app/element/userlist";
import { Channels } from "./channels";
import { channels, messages, users } from "./data";
import { Users } from "./users";
import "./chat.less";
class ChatModel {
viewType: string;
channels: MenuItem[];
users: UserStatus[];
messages: ChatMessage[];
constructor(blockId: string) {
this.viewType = "chat";
this.channels = channels;
this.messages = messages;
this.users = users;
}
}
function makeChatModel(blockId: string): ChatModel {
const cpuPlotViewModel = new ChatModel(blockId);
return cpuPlotViewModel;
}
interface ChatProps {
model: ChatModel;
}
const Chat = ({ model }: ChatProps) => {
const { channels, users, messages } = model;
return (
<div className="chat-view">
<Channels channels={channels}></Channels>
<div className="chat-section">
<ChatMessages messages={messages}></ChatMessages>
</div>
<Users users={users}></Users>
</div>
);
};
export { Chat, ChatModel, makeChatModel };

View File

@ -0,0 +1,46 @@
// ChatBox Component
import { EmojiPalette } from "@/app/element/emojipalette";
import { Input } from "@/app/element/input";
import { InputDecoration } from "@/app/element/inputdecoration";
import React, { useRef, useState } from "react";
interface ChatBoxProps {
onSendMessage: (message: string) => void;
}
const ChatBox: React.FC<ChatBoxProps> = ({ onSendMessage }) => {
const [message, setMessage] = useState("");
const anchorRef = useRef<HTMLButtonElement>(null);
const scopeRef = useRef<HTMLDivElement>(null);
const handleInputChange = (value: string) => {
setMessage(value);
};
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === "Enter" && message.trim() !== "") {
onSendMessage(message);
setMessage("");
}
};
return (
<div ref={scopeRef} className="chatbox">
<Input
value={message}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
placeholder="Type a message..."
decoration={{
endDecoration: (
<InputDecoration>
<EmojiPalette scopeRef={scopeRef} className="emoji-palette" />
</InputDecoration>
),
}}
/>
</div>
);
};
export { ChatBox };

View File

@ -0,0 +1,226 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { ChatMessage } from "@/app/element/chatmessages";
import { MenuItem } from "@/app/element/menu";
import { UserStatus } from "@/app/element/userlist";
export const channels: MenuItem[] = [
{
text: "Aurora Streams",
icon: "#",
onClick: () => console.log("Aurora Streams clicked"),
},
{
text: "Crimson Oasis",
onClick: () => console.log("Crimson Oasis clicked"),
children: [
{
text: "Golden Dunes",
icon: "#",
onClick: () => console.log("Golden Dunes clicked"),
},
{
text: "Emerald Springs",
icon: "#",
onClick: () => console.log("Emerald Springs clicked"),
},
{
text: "Ruby Cascades",
icon: "#",
onClick: () => console.log("Ruby Cascades clicked"),
},
{
text: "Sapphire Falls",
icon: "#",
onClick: () => console.log("Sapphire Falls clicked"),
},
],
},
{
text: "Velvet Horizon",
onClick: () => console.log("Velvet Horizon clicked"),
children: [
{
text: "Amber Skies",
icon: "#",
onClick: () => console.log("Amber Skies clicked"),
},
],
},
{
text: "Mystic Meadows",
icon: "#",
onClick: () => console.log("Mystic Meadows clicked"),
},
{
text: "Celestial Grove",
icon: "#",
onClick: () => console.log("Celestial Grove clicked"),
},
{
text: "Twilight Whisper",
icon: "#",
onClick: () => console.log("Twilight Whisper clicked"),
},
{
text: "Starlit Haven",
onClick: () => console.log("Starlit Haven clicked"),
children: [
{
text: "Moonlit Trail",
icon: "#",
onClick: () => console.log("Moonlit Trail clicked"),
},
],
},
{
text: "Silver Mist",
icon: "#",
onClick: () => console.log("Silver Mist clicked"),
},
{
text: "Eclipse Haven",
onClick: () => console.log("Eclipse Haven clicked"),
children: [
{
text: "Obsidian Wave",
icon: "#",
onClick: () => console.log("Obsidian Wave clicked"),
},
{
text: "Ivory Shore",
icon: "#",
onClick: () => console.log("Ivory Shore clicked"),
},
{
text: "Azure Tide",
icon: "#",
onClick: () => console.log("Azure Tide clicked"),
},
],
},
{
text: "Dragon's Peak",
icon: "#",
onClick: () => console.log("Dragon's Peak clicked"),
},
{
text: "Seraph's Wing",
icon: "#",
onClick: () => console.log("Seraph's Wing clicked"),
},
{
text: "Frozen Abyss",
icon: "#",
onClick: () => console.log("Frozen Abyss clicked"),
},
{
text: "Radiant Blossom",
icon: "#",
onClick: () => console.log("Radiant Blossom clicked"),
},
{
text: "Whispering Pines",
icon: "#",
onClick: () => console.log("Whispering Pines clicked"),
children: [
{
text: "Cedar Haven",
icon: "#",
onClick: () => console.log("Cedar Haven clicked"),
},
],
},
{
text: "Scarlet Veil",
icon: "#",
onClick: () => console.log("Scarlet Veil clicked"),
},
{
text: "Onyx Spire",
icon: "#",
onClick: () => console.log("Onyx Spire clicked"),
},
{
text: "Violet Enclave",
onClick: () => console.log("Violet Enclave clicked"),
children: [
{
text: "Indigo Haven",
icon: "#",
onClick: () => console.log("Indigo Haven clicked"),
},
{
text: "Amethyst Hollow",
icon: "#",
onClick: () => console.log("Amethyst Hollow clicked"),
},
{
text: "Crimson Glow",
icon: "#",
onClick: () => console.log("Crimson Glow clicked"),
},
],
},
];
export const users: UserStatus[] = [
{
text: "John Doe",
status: "online",
avatarUrl: "https://via.placeholder.com/50",
onClick: () => console.log("John Doe clicked"),
},
{
text: "Jane Smith",
status: "busy",
onClick: () => console.log("Jane Smith clicked"),
},
{
text: "Robert Brown",
status: "away",
avatarUrl: "https://via.placeholder.com/50",
onClick: () => console.log("Robert Brown clicked"),
},
{
text: "Alice Lambert",
status: "offline",
onClick: () => console.log("Alice Lambert clicked"),
},
];
export const messages: ChatMessage[] = [
{
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",
},
];

View File

@ -0,0 +1,6 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
.user-list {
max-width: 250px;
}

View File

@ -0,0 +1,12 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { Menu } from "@/app/element/menu";
import { UserStatus } from "@/app/element/userlist";
import "./users.less";
const Users = ({ users }: { users: UserStatus[] }) => {
return <Menu className="user-list" items={users}></Menu>;
};
export { Users };

View File

@ -1,27 +0,0 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { ChatMessage, ChatMessages } from "@/app/element/chatmessages";
import { Menu, MenuItem } from "@/app/element/menu";
import { UserStatus } from "@/app/element/userlist";
import "./chatview.less";
interface ChatViewProps {
channels: MenuItem[];
users: UserStatus[];
messages: ChatMessage[];
}
const ChatView = ({ channels, users, messages }: ChatViewProps) => {
return (
<div className="chat-view">
<Menu items={channels}></Menu>
<div className="chat-section">
<ChatMessages messages={messages}></ChatMessages>
</div>
<Menu items={users}></Menu>
</div>
);
};
export { ChatView };

View File

@ -1,303 +0,0 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { ChatMessage } from "@/app/element/chatmessages";
import { MenuItem } from "@/app/element/menu";
import { UserStatus } from "@/app/element/userlist";
export const channels: MenuItem[] = [
{
text: "Channel 1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 1 clicked"),
},
{
text: "Channel 2",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 2 clicked"),
children: [
{
text: "Channel 2.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 2.1 clicked"),
children: [
{
text: "Channel 2.1.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 2.1.1 clicked"),
},
{
text: "Channel 2.1.2",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 2.1.2 clicked"),
},
],
},
{
text: "Channel 2.2",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 2.2 clicked"),
},
],
},
{
text: "Channel 3",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 3 clicked"),
children: [
{
text: "Channel 3.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 3.1 clicked"),
},
],
},
{
text: "Channel 4",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 4 clicked"),
},
{
text: "Channel 5",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 5 clicked"),
children: [
{
text: "Channel 5.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 5.1 clicked"),
children: [
{
text: "Channel 5.1.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 5.1.1 clicked"),
},
{
text: "Channel 5.1.2",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 5.1.2 clicked"),
children: [
{
text: "Channel 5.1.2.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 5.1.2.1 clicked"),
},
],
},
],
},
],
},
{
text: "Channel 6",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 6 clicked"),
},
{
text: "Channel 7",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 7 clicked"),
children: [
{
text: "Channel 7.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 7.1 clicked"),
},
],
},
{
text: "Channel 8",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 8 clicked"),
},
{
text: "Channel 9",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 9 clicked"),
children: [
{
text: "Channel 9.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 9.1 clicked"),
children: [
{
text: "Channel 9.1.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 9.1.1 clicked"),
},
{
text: "Channel 9.1.2",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 9.1.2 clicked"),
},
],
},
],
},
{
text: "Channel 10",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 10 clicked"),
},
{
text: "Channel 11",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 11 clicked"),
},
{
text: "Channel 12",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 12 clicked"),
},
{
text: "Channel 13",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 13 clicked"),
},
{
text: "Channel 14",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 14 clicked"),
children: [
{
text: "Channel 14.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 14.1 clicked"),
},
],
},
{
text: "Channel 15",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 15 clicked"),
},
{
text: "Channel 16",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 16 clicked"),
},
{
text: "Channel 17",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 17 clicked"),
children: [
{
text: "Channel 17.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 17.1 clicked"),
children: [
{
text: "Channel 17.1.1",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 17.1.1 clicked"),
},
{
text: "Channel 17.1.2",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 17.1.2 clicked"),
},
],
},
],
},
{
text: "Channel 18",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 18 clicked"),
},
{
text: "Channel 19",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 19 clicked"),
},
{
text: "Channel 20",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 20 clicked"),
},
{
text: "Channel 21",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 21 clicked"),
},
{
text: "Channel 22",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 22 clicked"),
},
{
text: "Channel 23",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 23 clicked"),
},
{
text: "Channel 24",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 24 clicked"),
},
{
text: "Channel 25",
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
onClick: () => console.log("Channel 25 clicked"),
},
];
export const users: UserStatus[] = [
{
text: "John Doe",
status: "online",
avatarUrl: "https://via.placeholder.com/50",
onClick: () => console.log("John Doe clicked"),
},
{
text: "Jane Smith",
status: "busy",
onClick: () => console.log("Jane Smith clicked"),
},
{
text: "Robert Brown",
status: "away",
avatarUrl: "https://via.placeholder.com/50",
onClick: () => console.log("Robert Brown clicked"),
},
{
text: "Alice Lambert",
status: "offline",
onClick: () => console.log("Alice Lambert clicked"),
},
];
export const messages: ChatMessage[] = [
{
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",
},
];

View File

@ -50,5 +50,15 @@
"view": "cpuplot"
}
}
},
"defwidget@chat": {
"display:order": 6,
"icon": "comment",
"label": "chat",
"blockdef": {
"meta": {
"view": "chat"
}
}
}
}