add new context menu implementation

This commit is contained in:
jeffvli
2025-11-15 04:22:06 -08:00
parent ec0590c79a
commit 8eb90ebf06
47 changed files with 2826 additions and 1593 deletions
@@ -1,35 +0,0 @@
.container {
position: absolute;
z-index: 1000;
padding: var(--theme-spacing-xs);
background: var(--theme-colors-surface);
border: 1px solid var(--theme-colors-border);
border-radius: var(--theme-radius-md);
box-shadow: 2px 2px 10px 2px rgb(0 0 0 / 40%);
}
.context-menu-button {
display: flex;
padding: var(--theme-spacing-sm);
font-family: var(--theme-content-font-family);
font-size: var(--theme-font-size-sm);
font-weight: 500;
color: var(--theme-colors-surface-foreground);
text-align: left;
cursor: default;
background: var(--theme-colors-surface);
border: none;
&:hover {
background: lighten(var(--theme-colors-surface), 10%);
}
&:disabled {
background: transparent;
opacity: 0.6;
}
}
.left {
margin-right: 3rem;
}
@@ -1,85 +0,0 @@
import { motion, Variants } from 'motion/react';
import { ComponentPropsWithoutRef, forwardRef, ReactNode, Ref } from 'react';
import styles from './context-menu.module.css';
import { Group } from '/@/shared/components/group/group';
interface ContextMenuProps {
children: ReactNode;
maxWidth?: number;
minWidth?: number;
xPos: number;
yPos: number;
}
export const ContextMenuButton = forwardRef(
(
{
children,
leftIcon,
rightIcon,
...props
}: ComponentPropsWithoutRef<'button'> & {
leftIcon?: ReactNode;
rightIcon?: ReactNode;
},
ref: any,
) => {
return (
<button
{...props}
className={styles.contextMenuButton}
disabled={props.disabled}
key={props.key}
onClick={props.onClick}
ref={ref}
>
<Group justify="space-between" w="100%">
<Group className={styles.left} gap="md">
{leftIcon}
{children}
</Group>
{rightIcon}
</Group>
</button>
);
},
);
const variants: Variants = {
closed: {
opacity: 0,
transition: {
duration: 0.1,
},
},
open: {
opacity: 1,
transition: {
duration: 0.1,
},
},
};
export const ContextMenu = forwardRef(
({ children, maxWidth, minWidth, xPos, yPos }: ContextMenuProps, ref: Ref<HTMLDivElement>) => {
return (
<motion.div
animate="open"
className={styles.container}
initial="closed"
ref={ref}
style={{
left: xPos,
maxWidth,
minWidth,
top: yPos,
}}
variants={variants}
>
{children}
</motion.div>
);
},
);
@@ -4,6 +4,7 @@ import { useNavigate } from 'react-router';
import { getTitlePath } from '/@/renderer/components/item-list/helpers/get-title-path';
import { ItemListStateItemWithRequiredProperties } from '/@/renderer/components/item-list/helpers/item-list-state';
import { DefaultItemControlProps, ItemControls } from '/@/renderer/components/item-list/types';
import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller';
import { usePlayer } from '/@/renderer/features/player/context/player-context';
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
import { Play, TableColumn } from '/@/shared/types/types';
@@ -230,8 +231,38 @@ export const useDefaultItemListControls = (args?: UseDefaultItemListControlsArgs
player.setFavorite(item._serverId, [item.id], itemType, favorite);
},
onMore: ({ internalState, item, itemType }: DefaultItemControlProps) => {
console.log('handleItemMore', item, itemType, internalState);
onMore: ({ event, internalState, item, itemType }: DefaultItemControlProps) => {
if (!item || !internalState || !event) {
return;
}
const rowId = internalState.extractRowId(item);
if (!rowId) return;
// If none selected, select this item
if (internalState.getSelected().length === 0) {
internalState.setSelected([item]);
return ContextMenuController.call({
cmd: { items: [item] as any[], type: itemType as any },
event,
});
}
// If this item is not already selected, replace the selection with this item
else if (!internalState.isSelected(rowId)) {
internalState.setSelected([item]);
return ContextMenuController.call({
cmd: { items: [item] as any[], type: itemType as any },
event,
});
}
const selectedItems = internalState.getSelected();
return ContextMenuController.call({
cmd: { items: selectedItems as any[], type: itemType as any },
event,
});
},
onPlay: ({