diff --git a/frontend/app/element/contextmenu.stories.tsx b/frontend/app/element/contextmenu.stories.tsx index 1aa0e065c..6dd332797 100644 --- a/frontend/app/element/contextmenu.stories.tsx +++ b/frontend/app/element/contextmenu.stories.tsx @@ -56,7 +56,7 @@ const items = [ ]; const meta = { - title: "Elements/Menu", + title: "Elements/ContextMenu", component: ContextMenu, args: { items: [], diff --git a/frontend/app/element/list.less b/frontend/app/element/menu.less similarity index 83% rename from frontend/app/element/list.less rename to frontend/app/element/menu.less index 5a3105541..ec62d4e31 100644 --- a/frontend/app/element/list.less +++ b/frontend/app/element/menu.less @@ -1,35 +1,35 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -.list { +.menu { list-style: none; padding: 0; } -.list-item { +.menu-item { padding: 10px; cursor: pointer; user-select: none; padding: 0; } -.list-item-button { +.menu-item-button { display: flex; align-items: center; justify-content: space-between; width: 100%; } -.list-item-content { +.menu-item-content { display: flex; align-items: center; } -.list-item-icon { +.menu-item-icon { margin-right: 10px; /* Space between icon and text */ } -.list-item-text { +.menu-item-text { text-decoration: none; } @@ -46,7 +46,7 @@ display: none; } -.list-item-button { +.menu-item-button { padding: 10px; color: var(--main-text-color); @@ -56,6 +56,6 @@ } } -.list-item-button.clickable:hover { +.menu-item-button.clickable:hover { background-color: #f0f0f0; } diff --git a/frontend/app/element/list.stories.tsx b/frontend/app/element/menu.stories.tsx similarity index 95% rename from frontend/app/element/list.stories.tsx rename to frontend/app/element/menu.stories.tsx index 851cf435e..3e7c4eb02 100644 --- a/frontend/app/element/list.stories.tsx +++ b/frontend/app/element/menu.stories.tsx @@ -3,13 +3,13 @@ import { Meta, StoryObj } from "@storybook/react"; import { Avatar } from "./avatar"; -import { List } from "./list"; +import { Menu } from "./menu"; -import "./list.less"; +import "./menu.less"; -const meta: Meta = { - title: "Elements/List", - component: List, +const meta: Meta = { + title: "Elements/Menu", + component: Menu, argTypes: { items: { control: "object" }, renderItem: { control: false }, @@ -145,7 +145,7 @@ export const Default: Story = { }, render: (args) => ( - + ), }; @@ -156,7 +156,7 @@ export const NestedList: Story = { }, render: (args) => ( - + ), }; @@ -168,7 +168,7 @@ export const CustomRender: Story = { }, render: (args) => ( - + ), }; @@ -179,7 +179,7 @@ export const WithClickHandlers: Story = { }, render: (args) => ( - + ), }; @@ -190,7 +190,7 @@ export const NestedWithClickHandlers: Story = { }, render: (args) => ( - + ), }; @@ -224,7 +224,7 @@ export const WithAvatars: Story = { }, render: (args) => ( - + ), }; diff --git a/frontend/app/element/list.tsx b/frontend/app/element/menu.tsx similarity index 63% rename from frontend/app/element/list.tsx rename to frontend/app/element/menu.tsx index 3221c8346..94712eef8 100644 --- a/frontend/app/element/list.tsx +++ b/frontend/app/element/menu.tsx @@ -3,48 +3,48 @@ import clsx from "clsx"; import React, { memo, useState } from "react"; -import "./list.less"; +import "./menu.less"; -interface ListItem { +interface MenuItem { text: string; icon?: React.ReactNode; - children?: ListItem[]; + children?: MenuItem[]; onClick?: () => void; } -interface ListProps { - items: ListItem[]; +interface MenuProps { + items: MenuItem[]; className?: string; - renderItem?: (item: ListItem, isOpen: boolean, handleClick: () => void) => React.ReactNode; + renderItem?: (item: MenuItem, isOpen: boolean, handleClick: () => void) => React.ReactNode; } -const List = memo(({ items, className, renderItem }: ListProps) => { +const Menu = memo(({ items, className, renderItem }: MenuProps) => { const [open, setOpen] = useState<{ [key: string]: boolean }>({}); // Helper function to generate a unique key for each item based on its path in the hierarchy - const getItemKey = (item: ListItem, path: string) => `${path}-${item.text}`; + const getItemKey = (item: MenuItem, path: string) => `${path}-${item.text}`; - const handleClick = (item: ListItem, itemKey: string) => { + const handleClick = (item: MenuItem, itemKey: string) => { setOpen((prevState) => ({ ...prevState, [itemKey]: !prevState[itemKey] })); if (item.onClick) { item.onClick(); } }; - const renderListItem = (item: ListItem, index: number, path: string) => { - const itemKey = getItemKey(item, path); // Generate unique key based on the path + const renderListItem = (item: MenuItem, index: number, path: string) => { + const itemKey = getItemKey(item, path); const isOpen = open[itemKey] === true; const hasChildren = item.children && item.children.length > 0; return ( -
  • +
  • {renderItem ? ( renderItem(item, isOpen, () => handleClick(item, itemKey)) ) : ( -
    handleClick(item, itemKey)}> -
    -
    {item.icon}
    -
    {item.text}
    +
    handleClick(item, itemKey)}> +
    +
    {item.icon}
    +
    {item.text}
    {hasChildren && ( @@ -62,9 +62,9 @@ const List = memo(({ items, className, renderItem }: ListProps) => { ); }; - return
      {items.map((item, index) => renderListItem(item, index, "root"))}
    ; + return
      {items.map((item, index) => renderListItem(item, index, "root"))}
    ; }); -List.displayName = "List"; +Menu.displayName = "Menu"; -export { List }; +export { Menu }; diff --git a/frontend/app/view/chatview/chatview.tsx b/frontend/app/view/chatview/chatview.tsx index df7b10174..26559d17a 100644 --- a/frontend/app/view/chatview/chatview.tsx +++ b/frontend/app/view/chatview/chatview.tsx @@ -1,16 +1,16 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 import { Avatar } from "@/app/element/avatar" -import { List } from "@/app/element/list" +import { List } from "@/app/element/menu" import { ChatItem } from "./chatitem" -import type { Channel, Message, User } from "./data" +import type { MessageListItem, UserListItem } from "./data" import "./Layout.css"; interface ChatViewProps { - channels: Channel[]; - users: User[]; - messages: Message[]; + channels: ListItem[]; + users: UserListItem[]; + messages: MessageListItem[]; } const ChatView = ({ channels, users, messages }: ChatViewProps) => { @@ -33,7 +33,7 @@ const ChatView = ({ channels, users, messages }: ChatViewProps) => { ))}
    - }> + }>
    ); diff --git a/frontend/app/view/chatview/data.tsx b/frontend/app/view/chatview/data.tsx index 41af93e28..05bd0cd38 100644 --- a/frontend/app/view/chatview/data.tsx +++ b/frontend/app/view/chatview/data.tsx @@ -2,14 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Avatar } from "@/app/element/avatar"; -export type Channel = { - text: string; - icon: JSX.Element; - onClick: () => void; - children?: Channel[]; -}; - -export const channels: Channel[] = [ +export const channels: ListItem[] = [ { text: "Channel 1", icon: , @@ -246,13 +239,11 @@ export const channels: Channel[] = [ }, ]; -export type User = { - name: string; +export type UserListItem = ListItem & { status: "online" | "busy" | "away" | "offline"; - onClick: () => void; }; -export const users = [ +export const users: UserListItem[] = [ { text: "John Doe", status: "online", @@ -279,12 +270,11 @@ export const users = [ }, ]; -export type Message = { - text: string; +export type MessageListItem = ListItem & { timestamp: string; }; -export const messages: Message[] = [ +export const messages: MessageListItem[] = [ { text: "Message 1 content", timestamp: "2024-09-24 17:02:12" }, { text: "Message 2 content", timestamp: "2024-07-11 04:17:12" }, { text: "Message 3 content", timestamp: "2024-07-30 15:32:12" },