mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-15 01:32:17 +01:00
dropdown stopries
This commit is contained in:
parent
0525efc1ce
commit
f7d8ff3665
@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2023, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import type { Meta, StoryObj } from "@storybook/react";
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
import { fn } from "@storybook/test";
|
import { fn } from "@storybook/test";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
@ -8,7 +8,7 @@ import ReactDOM from "react-dom";
|
|||||||
import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions";
|
import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions";
|
||||||
import "./contextmenu.less";
|
import "./contextmenu.less";
|
||||||
|
|
||||||
type MenuItem = {
|
export type MenuItem = {
|
||||||
label: string;
|
label: string;
|
||||||
subItems?: MenuItem[];
|
subItems?: MenuItem[];
|
||||||
onClick?: (e) => void;
|
onClick?: (e) => void;
|
||||||
|
60
frontend/app/element/dropdown.stories.tsx
Normal file
60
frontend/app/element/dropdown.stories.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2023, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
import { MenuItem } from "./contextmenu";
|
||||||
|
import { Dropdown } from "./dropdown";
|
||||||
|
|
||||||
|
const items: MenuItem[] = [
|
||||||
|
{ label: "Option 1", onClick: () => console.log("Clicked Option 1") },
|
||||||
|
{
|
||||||
|
label: "Option 2",
|
||||||
|
subItems: [
|
||||||
|
{ label: "Option 2.1", onClick: () => console.log("Clicked Option 2.1") },
|
||||||
|
{ label: "Option 2.2", onClick: () => console.log("Clicked Option 2.2") },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ label: "Option 3", onClick: () => console.log("Clicked Option 3") },
|
||||||
|
];
|
||||||
|
|
||||||
|
const meta: Meta<typeof Dropdown> = {
|
||||||
|
title: "Elements/Dropdown",
|
||||||
|
component: Dropdown,
|
||||||
|
args: {
|
||||||
|
label: "Dropdown Label",
|
||||||
|
items: items,
|
||||||
|
className: "",
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
label: {
|
||||||
|
description: "Label for the dropdown button",
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
description: "Menu items for the dropdown",
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
description: "Custom class for dropdown styling",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Dropdown>;
|
||||||
|
|
||||||
|
export const DefaultDropdown: Story = {
|
||||||
|
render: (args) => {
|
||||||
|
const scopeRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={scopeRef} style={{ padding: "20px", height: "300px", border: "2px solid black" }}>
|
||||||
|
<Dropdown {...args} scopeRef={scopeRef} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
label: "Options",
|
||||||
|
items: items,
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import clsx from "clsx";
|
||||||
|
import { memo, useRef, useState } from "react";
|
||||||
|
import { Button } from "./button";
|
||||||
|
import { ContextMenu, MenuItem } from "./contextmenu";
|
||||||
|
|
||||||
|
import "./dropdown.less";
|
||||||
|
|
||||||
|
interface DropdownProps {
|
||||||
|
label: string;
|
||||||
|
items: MenuItem[];
|
||||||
|
scopeRef: React.RefObject<any>;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Dropdown = memo(({ label, className, items, scopeRef }: DropdownProps) => {
|
||||||
|
const anchorRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const [isMenuVisible, setIsMenuVisible] = useState(false);
|
||||||
|
|
||||||
|
const handleAnchorClick = () => {
|
||||||
|
setIsMenuVisible((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapItemsWithClick = (items: any[]) => {
|
||||||
|
return items.map((item) => ({
|
||||||
|
...item,
|
||||||
|
onClick: () => {
|
||||||
|
if (item.onClick) {
|
||||||
|
item.onClick();
|
||||||
|
setIsMenuVisible(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
subItems: item.subItems ? mapItemsWithClick(item.subItems) : undefined,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx("dropdown", className)}>
|
||||||
|
<Button
|
||||||
|
ref={anchorRef}
|
||||||
|
className="grey border-radius-3 vertical-padding-6 horizontal-padding-8"
|
||||||
|
style={{ borderColor: isMenuVisible ? "var(--accent-color)" : "transparent" }}
|
||||||
|
onClick={handleAnchorClick}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
<i className="fa-sharp fa-solid fa-angle-down" style={{ marginLeft: 4 }}></i>
|
||||||
|
</Button>
|
||||||
|
{isMenuVisible && (
|
||||||
|
<ContextMenu
|
||||||
|
items={items}
|
||||||
|
setVisibility={(visible) => setIsMenuVisible(visible)}
|
||||||
|
anchorRef={anchorRef}
|
||||||
|
scopeRef={scopeRef}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Dropdown.displayName = "Dropdown";
|
||||||
|
|
||||||
|
export { Dropdown };
|
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import "channels.less";
|
||||||
|
|
||||||
|
const channels = [
|
||||||
|
{
|
||||||
|
text: "Channel 1",
|
||||||
|
icon: <i className="fa-sharp fa-solid fa-door-open"></i>,
|
||||||
|
onClick: () => console.log("Inbox clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Channel 2",
|
||||||
|
icon: <i className="fa-sharp fa-solid fa-paper-plane"></i>,
|
||||||
|
onClick: () => console.log("Sent Mail clicked"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Drafts",
|
||||||
|
icon: <i className="fa-sharp fa-solid fa-drafting-compass"></i>,
|
||||||
|
onClick: () => console.log("Drafts clicked"),
|
||||||
|
},
|
||||||
|
];
|
@ -1,248 +1,23 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
import { Avatar } from "@/app/element/avatar"
|
||||||
|
import { List } from "@/app/element/list"
|
||||||
|
import { ChatItem } from "./chatitem"
|
||||||
|
import type { Channel, Message, User } from "./data"
|
||||||
|
|
||||||
import "./Layout.css";
|
import "./Layout.css";
|
||||||
|
|
||||||
const channels = [
|
interface ChatViewProps {
|
||||||
{
|
channels: Channel[];
|
||||||
text: "Channel 1",
|
users: User[];
|
||||||
icon: <i className="fa-sharp fa-solid fa-wave"></i>,
|
messages: Message[];
|
||||||
onClick: () => console.log("Channel 1 clicked"),
|
}
|
||||||
},
|
|
||||||
{
|
const ChatView = ({ channels, users, messages }: ChatViewProps) => {
|
||||||
text: "Channel 2",
|
const renderChatItem =
|
||||||
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"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const Layout = ({ columns }) => {
|
|
||||||
return (
|
return (
|
||||||
<div className="layout">
|
<div className="chat-view">
|
||||||
{columns.map((column, index) => (
|
{columns.map((column, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
@ -256,8 +31,12 @@ const Layout = ({ columns }) => {
|
|||||||
{column.content}
|
{column.content}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
<List items={channels}></List>
|
||||||
|
<div className="chat-section">
|
||||||
|
<List items={messages} renderItem={<ChatItem />}></List>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Layout;
|
export { ChatView };
|
||||||
|
Loading…
Reference in New Issue
Block a user