mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-01 23:58:36 -05:00
Move app to apps/web-react in pnpm workspace layout
This commit is contained in:
110
apps/web-react/app/components/elements/Menu.tsx
Normal file
110
apps/web-react/app/components/elements/Menu.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import clsx from "clsx";
|
||||
import {
|
||||
Header,
|
||||
Menu,
|
||||
MenuItem,
|
||||
type MenuItemProps,
|
||||
MenuTrigger,
|
||||
Popover,
|
||||
type PopoverProps,
|
||||
Section,
|
||||
} from "react-aria-components";
|
||||
import { Image } from "../Image";
|
||||
import styles from "./Menu.module.css";
|
||||
|
||||
interface SendouMenuProps {
|
||||
trigger: React.ReactNode;
|
||||
scrolling?: boolean;
|
||||
opensLeft?: boolean;
|
||||
children: React.ReactNode;
|
||||
popoverClassName?: string;
|
||||
placement?: PopoverProps["placement"];
|
||||
}
|
||||
|
||||
export function SendouMenu({
|
||||
children,
|
||||
trigger,
|
||||
opensLeft,
|
||||
scrolling,
|
||||
placement,
|
||||
}: SendouMenuProps) {
|
||||
return (
|
||||
<MenuTrigger>
|
||||
{trigger}
|
||||
<Popover
|
||||
placement={placement}
|
||||
className={clsx(styles.popover, "scrollbar", {
|
||||
[styles.scrolling]: scrolling,
|
||||
[styles.popoverOpensLeft]: !opensLeft,
|
||||
})}
|
||||
>
|
||||
<Menu className={styles.itemsContainer}>{children}</Menu>
|
||||
</Popover>
|
||||
</MenuTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
export interface SendouMenuItemProps extends MenuItemProps {
|
||||
icon?: React.ReactNode;
|
||||
imagePath?: string;
|
||||
isActive?: boolean;
|
||||
isDestructive?: boolean;
|
||||
}
|
||||
|
||||
export function SendouMenuSection({
|
||||
children,
|
||||
headerText,
|
||||
headerClassName,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
headerText?: React.ReactNode;
|
||||
headerClassName?: string;
|
||||
}) {
|
||||
return (
|
||||
<Section>
|
||||
{headerText ? (
|
||||
<Header className={clsx(styles.menuHeader, headerClassName)}>
|
||||
{headerText}
|
||||
</Header>
|
||||
) : null}
|
||||
{children}
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
export function SendouMenuItem(props: SendouMenuItemProps) {
|
||||
const textValue =
|
||||
props.textValue ??
|
||||
(typeof props.children === "string" ? props.children : undefined);
|
||||
return (
|
||||
<MenuItem
|
||||
{...props}
|
||||
textValue={textValue}
|
||||
className={({ isSelected, isDisabled }) =>
|
||||
clsx(styles.item, {
|
||||
[styles.itemSelected]: isSelected,
|
||||
[styles.itemDisabled]: isDisabled,
|
||||
[styles.itemActive]: props.isActive,
|
||||
[styles.itemDestructive]: props.isDestructive,
|
||||
})
|
||||
}
|
||||
>
|
||||
{/** biome-ignore lint/complexity/noUselessFragments: Biome v2 migration */}
|
||||
<>
|
||||
{props.icon ? (
|
||||
<span className={styles.itemIcon}>{props.icon}</span>
|
||||
) : null}
|
||||
{props.imagePath ? (
|
||||
<Image
|
||||
path={props.imagePath}
|
||||
alt=""
|
||||
width={20}
|
||||
height={20}
|
||||
className={styles.itemImg}
|
||||
/>
|
||||
) : null}
|
||||
{props.children}
|
||||
</>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user