dropdown stopries

This commit is contained in:
Red Adaya 2024-10-04 20:56:21 +08:00
parent 0525efc1ce
commit f7d8ff3665
6 changed files with 168 additions and 240 deletions

View File

@ -1,3 +1,6 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import type { Meta, StoryObj } from "@storybook/react";
import { fn } from "@storybook/test";
import { useEffect, useRef, useState } from "react";

View File

@ -8,7 +8,7 @@ import ReactDOM from "react-dom";
import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions";
import "./contextmenu.less";
type MenuItem = {
export type MenuItem = {
label: string;
subItems?: MenuItem[];
onClick?: (e) => void;

View 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,
},
};

View File

@ -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 };

View File

@ -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"),
},
];

View File

@ -1,248 +1,23 @@
// Copyright 2024, Command Line Inc.
// 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";
const channels = [
{
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"),
},
];
interface ChatViewProps {
channels: Channel[];
users: User[];
messages: Message[];
}
const ChatView = ({ channels, users, messages }: ChatViewProps) => {
const renderChatItem =
const Layout = ({ columns }) => {
return (
<div className="layout">
<div className="chat-view">
{columns.map((column, index) => (
<div
key={index}
@ -256,8 +31,12 @@ const Layout = ({ columns }) => {
{column.content}
</div>
))}
<List items={channels}></List>
<div className="chat-section">
<List items={messages} renderItem={<ChatItem />}></List>
</div>
</div>
);
};
export default Layout;
export { ChatView };