UI
This commit is contained in:
parent
98ca3e239f
commit
b9a10e7585
64
apps/ui/web/src/app/features/ContextMenu.tsx
Normal file
64
apps/ui/web/src/app/features/ContextMenu.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "../store";
|
||||
import { setContextMenuVisible } from "../store/context-menu-slice";
|
||||
import { Box, Typography, useTheme } from "@mui/material";
|
||||
|
||||
export interface ContextMenuItem {
|
||||
actionIndex: number,
|
||||
icon: JSX.Element | null,
|
||||
text: string
|
||||
}
|
||||
|
||||
type NullableContextMenuActionEvent<T> = ContextMenuActionEvent<T> | null;
|
||||
export interface ContextMenuActionEvent<T> {
|
||||
selected: (actionIndex: number | null, value: T | null) => void;
|
||||
}
|
||||
|
||||
export default function ContextMenu<T>({ actionItems, row = null, onContextMenuItemClicked} : { actionItems: ContextMenuItem[], row?: T | null, onContextMenuItemClicked?: ContextMenuActionEvent<T>}) {
|
||||
const muiTheme = useTheme();
|
||||
const state = useSelector((state: RootState) => state.contextMenu)
|
||||
const dispatch = useDispatch();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [position, setPosition] = useState({ top: 0, left: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
setVisible(state.visible)
|
||||
const position = state.position
|
||||
if (position) {
|
||||
setPosition({top: position.y, left: position.x})
|
||||
}
|
||||
}, [state])
|
||||
|
||||
useEffect(() => {
|
||||
const handleClick = () => dispatch(setContextMenuVisible(false));
|
||||
window.addEventListener("click", handleClick);
|
||||
return () => {
|
||||
window.removeEventListener("click", handleClick);
|
||||
};
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{visible && (
|
||||
<Box className="contextmenu" sx={{
|
||||
top: position.top,
|
||||
left: position.left,
|
||||
backgroundColor: muiTheme.palette.action.selected,
|
||||
}}>
|
||||
{ actionItems.map((item, index) => (
|
||||
<Box className="contextMenuItem" display="flex" key={index} onClick={() => {
|
||||
onContextMenuItemClicked?.selected(item.actionIndex, row)
|
||||
}} >
|
||||
{item.icon}
|
||||
<Typography>{item.text}</Typography>
|
||||
</Box>
|
||||
))}
|
||||
{actionItems.length === 0 && (
|
||||
<Typography>Nothing to do..</Typography>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
31
apps/ui/web/src/app/store/context-menu-slice.ts
Normal file
31
apps/ui/web/src/app/store/context-menu-slice.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
|
||||
|
||||
interface ContextMenuPosition {
|
||||
x: number,
|
||||
y: number
|
||||
}
|
||||
|
||||
interface ContextMenuState {
|
||||
visible: boolean,
|
||||
position?: ContextMenuPosition
|
||||
}
|
||||
|
||||
const initialState: ContextMenuState = {
|
||||
visible: false
|
||||
}
|
||||
|
||||
const contextMenuSlice = createSlice({
|
||||
name: 'ContextMenu',
|
||||
initialState,
|
||||
reducers: {
|
||||
setContextMenuVisible(state, action: PayloadAction<boolean>) {
|
||||
state.visible = action.payload
|
||||
},
|
||||
setContextMenuPosition(state, action: PayloadAction<ContextMenuPosition>) {
|
||||
state.position = action.payload
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const { setContextMenuVisible, setContextMenuPosition } = contextMenuSlice.actions;
|
||||
export default contextMenuSlice.reducer;
|
||||
33
apps/ui/web/src/fileUtil.ts
Normal file
33
apps/ui/web/src/fileUtil.ts
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
export function canEncode(extension: string): boolean {
|
||||
const supported = [
|
||||
"mkv",
|
||||
"avi",
|
||||
"mp4",
|
||||
"wmv",
|
||||
"webm",
|
||||
"mov"
|
||||
]
|
||||
const found = supported.find((item) => item === extension)
|
||||
return (found) ? true : false;
|
||||
}
|
||||
|
||||
export function canExtract(extension: string): boolean {
|
||||
const supported = [
|
||||
"mkv"
|
||||
]
|
||||
const found = supported.find((item) => item === extension)
|
||||
return (found) ? true : false;
|
||||
}
|
||||
|
||||
export function canConvert(extension: string): boolean {
|
||||
const supported = [
|
||||
"ass",
|
||||
"srt",
|
||||
"vtt",
|
||||
"smi"
|
||||
]
|
||||
const found = supported.find((item) => item === extension)
|
||||
return (found) ? true : false;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user