add context menu, add context menu to video component
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
parent
0efd9ed1f8
commit
ed53ae1ea1
@ -0,0 +1,62 @@
|
||||
import useContextMenuStore from "@/hooks/useContextMenuStore";
|
||||
import { Component } from "@/typings/component";
|
||||
import { Listbox, ListboxItem } from "@nextui-org/listbox";
|
||||
import { useCallback, useEffect } from "react";
|
||||
|
||||
const Menu: Component = () => {
|
||||
const shouldShow = useContextMenuStore((state) => state.show);
|
||||
const menu = useContextMenuStore((state) => state.items);
|
||||
const hide = useContextMenuStore((state) => state.hide);
|
||||
|
||||
const location = useContextMenuStore((state) => state.location);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (shouldShow) hide();
|
||||
}, [hide, shouldShow]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("click", handleClick);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("click", handleClick);
|
||||
};
|
||||
}, [hide, shouldShow]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
top: location.y,
|
||||
left: location.x,
|
||||
display: shouldShow ? "block" : "none"
|
||||
}}
|
||||
className="bg-background border-small max-w-xs px-1 py-2 rounded-small border-default-200 absolute z-10"
|
||||
>
|
||||
<Listbox aria-label="Context Menu">
|
||||
{menu.map((item) => (
|
||||
<ListboxItem
|
||||
onClick={() => {
|
||||
if (item.onClick) {
|
||||
item.onClick();
|
||||
hide();
|
||||
}
|
||||
}}
|
||||
showDivider={item.showDivider}
|
||||
key={item.key}
|
||||
href={item.href}
|
||||
>
|
||||
{item.title}
|
||||
</ListboxItem>
|
||||
))}
|
||||
</Listbox>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ContextMenuProvider: Component = ({ children }) => {
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
<Menu />
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,23 +1,22 @@
|
||||
import useContextMenuStore from "@/hooks/useContextMenuStore";
|
||||
import { Component } from "@/typings/component";
|
||||
import { Listbox, ListboxItem } from "@nextui-org/listbox";
|
||||
|
||||
export interface ContextMenuItem {
|
||||
title: string;
|
||||
key: string;
|
||||
href?: string;
|
||||
onClick?: () => any;
|
||||
}
|
||||
import { ContextMenuItem } from "@/typings/contextMenu";
|
||||
|
||||
export const ContextMenu: Component<{ menu: ContextMenuItem[] }> = ({
|
||||
menu
|
||||
menu,
|
||||
children
|
||||
}) => {
|
||||
const showContextMenu = useContextMenuStore((state) => state.showContextMenu);
|
||||
|
||||
return (
|
||||
<Listbox aria-label="Context Menu">
|
||||
{menu.map((item) => (
|
||||
<ListboxItem onClick={item.onClick} key={item.key} href={item.href}>
|
||||
{item.title}
|
||||
</ListboxItem>
|
||||
))}
|
||||
</Listbox>
|
||||
<div
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
|
||||
showContextMenu(e.pageX, e.pageY, menu);
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { ContextMenuItem } from "@/typings/contextMenu";
|
||||
import { create } from "zustand";
|
||||
|
||||
interface Location {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface ContextMenuStore {
|
||||
show: boolean;
|
||||
location: Location;
|
||||
items: ContextMenuItem[];
|
||||
showContextMenu: (x: number, y: number, items: ContextMenuItem[]) => void;
|
||||
hide: () => void;
|
||||
}
|
||||
|
||||
const useContextMenuStore = create<ContextMenuStore>((set) => ({
|
||||
show: false,
|
||||
location: { x: 0, y: 0 },
|
||||
items: [],
|
||||
showContextMenu(x, y, items) {
|
||||
set({ show: true, location: { x, y }, items });
|
||||
},
|
||||
hide: () => set({ show: false })
|
||||
}));
|
||||
|
||||
export default useContextMenuStore;
|
@ -0,0 +1,7 @@
|
||||
export interface ContextMenuItem {
|
||||
title: string;
|
||||
key: string;
|
||||
showDivider?: boolean;
|
||||
href?: string;
|
||||
onClick?: () => any;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import { DateTime } from "luxon";
|
||||
|
||||
const formatUploadedTime = (uploaded: Date): string => {
|
||||
return DateTime.fromJSDate(uploaded).toRelative() ?? "";
|
||||
};
|
||||
|
||||
export default formatUploadedTime;
|
Loading…
Reference in new issue