mirror of
https://github.com/anidl/multi-downloader-nx.git
synced 2026-01-11 20:10:20 +00:00
Changes as discussed with sww
This commit is contained in:
parent
3683d93691
commit
fd10455400
5 changed files with 1679 additions and 1627 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -2,12 +2,15 @@ import { Box, List, ListItem, Typography, Divider, Dialog, Select, MenuItem, For
|
|||
import { CheckBox, CheckBoxOutlineBlank } from '@mui/icons-material';
|
||||
import React from 'react';
|
||||
import useStore from '../../../../hooks/useStore';
|
||||
import ContextMenu from '../../../reusable/ContextMenu';
|
||||
import { useSnackbar } from 'notistack';
|
||||
|
||||
|
||||
const EpisodeListing: React.FC = () => {
|
||||
const [store, dispatch] = useStore();
|
||||
|
||||
const [season, setSeason] = React.useState<'all'|string>('all');
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const seasons = React.useMemo(() => {
|
||||
const s: string[] = [];
|
||||
|
|
@ -72,6 +75,7 @@ const EpisodeListing: React.FC = () => {
|
|||
</ListItem>
|
||||
{store.episodeListing.filter((a) => season === 'all' ? true : a.season === season).map((item, index, { length }) => {
|
||||
const e = isNaN(parseInt(item.e)) ? item.e : parseInt(item.e);
|
||||
const idStr = `S${item.season}E${e}`
|
||||
const isSelected = selected.includes(e.toString());
|
||||
return <Box {...{ mouseData: isSelected }} key={`Episode_List_Item_${index}`} sx={{
|
||||
backdropFilter: isSelected ? 'brightness(1.5)' : '',
|
||||
|
|
@ -91,7 +95,7 @@ const EpisodeListing: React.FC = () => {
|
|||
<ListItem sx={{ display: 'grid', gridTemplateColumns: '25px 50px 1fr 5fr' }}>
|
||||
{ isSelected ? <CheckBox /> : <CheckBoxOutlineBlank /> }
|
||||
<Typography color='text.primary' sx={{ textAlign: 'center' }}>
|
||||
{e}
|
||||
{idStr}
|
||||
</Typography>
|
||||
<img style={{ width: 'inherit', maxHeight: '200px', minWidth: '150px' }} src={item.img} alt="thumbnail" />
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', pl: 1 }}>
|
||||
|
|
@ -160,4 +164,4 @@ const parseSelect = (s: string): string[] => {
|
|||
return [...new Set(ret)];
|
||||
};
|
||||
|
||||
export default EpisodeListing;
|
||||
export default EpisodeListing;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ const SearchBox: React.FC = () => {
|
|||
React.useEffect(() => {
|
||||
if (search.trim().length === 0)
|
||||
return setSearchResult({ isOk: true, value: [] });
|
||||
|
||||
|
||||
const timeOutId = setTimeout(async () => {
|
||||
if (search.trim().length > 3) {
|
||||
const s = await messageHandler?.search({search});
|
||||
|
|
@ -49,12 +49,13 @@ const SearchBox: React.FC = () => {
|
|||
<Box sx={{ m: 2 }}>
|
||||
<TextField ref={anchor} value={search} onClick={() => setFocus(true)} onChange={e => setSearch(e.target.value)} variant='outlined' label='Search' fullWidth />
|
||||
{searchResult !== undefined && searchResult.isOk && searchResult.value.length > 0 && focus &&
|
||||
<Paper sx={{ position: 'fixed', maxHeight: '50%', width: `${anchorBounding?.width}px`,
|
||||
<Paper sx={{ position: 'fixed', maxHeight: '50%', width: `${anchorBounding?.width}px`,
|
||||
left: anchorBounding?.x, top: (anchorBounding?.y ?? 0) + (anchorBounding?.height ?? 0), zIndex: 99, overflowY: 'scroll'}}>
|
||||
<List>
|
||||
{searchResult && searchResult.isOk ?
|
||||
searchResult.value.map((a, ind, arr) => {
|
||||
const imageRef = React.createRef<HTMLImageElement>();
|
||||
const summaryRef = React.createRef<HTMLParagraphElement>();
|
||||
return <Box key={a.id}>
|
||||
<ListItem className='listitem-hover' onClick={() => {
|
||||
selectItem(a.id);
|
||||
|
|
@ -68,7 +69,7 @@ const SearchBox: React.FC = () => {
|
|||
<Typography variant='h6' component='h6' color='text.primary' sx={{ }}>
|
||||
{a.name}
|
||||
</Typography>
|
||||
{a.desc && <Typography variant='caption' component='p' color='text.primary' sx={{ pt: 1, pb: 1 }}>
|
||||
{a.desc && <Typography variant='caption' component='p' color='text.primary' sx={{ pt: 1, pb: 1 }} ref={summaryRef}>
|
||||
{a.desc}
|
||||
</Typography>}
|
||||
{a.lang && <Typography variant='caption' component='p' color='text.primary' sx={{ }}>
|
||||
|
|
@ -90,8 +91,21 @@ const SearchBox: React.FC = () => {
|
|||
text: 'Open image in new tab',
|
||||
onClick: () => {
|
||||
window.open(a.image);
|
||||
}
|
||||
}
|
||||
} ]} popupItem={imageRef} />
|
||||
{a.desc &&
|
||||
<ContextMenu options={[
|
||||
{
|
||||
onClick: async () => {
|
||||
await navigator.clipboard.writeText(a.desc!);
|
||||
enqueueSnackbar('Copied summary to clipboard', {
|
||||
variant: 'info'
|
||||
})
|
||||
},
|
||||
text: "Copy summary to clipboard"
|
||||
}
|
||||
]} popupItem={summaryRef} />
|
||||
}
|
||||
{(ind < arr.length - 1) && <Divider />}
|
||||
</Box>;
|
||||
})
|
||||
|
|
@ -102,4 +116,4 @@ const SearchBox: React.FC = () => {
|
|||
</ClickAwayListener>;
|
||||
};
|
||||
|
||||
export default SearchBox;
|
||||
export default SearchBox;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const buttonSx: SxProps = {
|
|||
|
||||
function ContextMenu<T extends HTMLElement, >(props: ContextMenuProps<T>) {
|
||||
const [anchor, setAnchor] = React.useState( { x: 0, y: 0 } );
|
||||
|
||||
|
||||
const [show, setShow] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
|
|
@ -37,16 +37,16 @@ function ContextMenu<T extends HTMLElement, >(props: ContextMenuProps<T>) {
|
|||
};
|
||||
ref.current.addEventListener('contextmenu', listener);
|
||||
|
||||
return () => {
|
||||
return () => {
|
||||
if (ref.current)
|
||||
ref.current.removeEventListener('contextmenu', listener);
|
||||
};
|
||||
}, [ props.popupItem ]);
|
||||
|
||||
return show ? <Box sx={{ zIndex: 9999, p: 1, background: 'rgba(0, 0, 0, 0.75)', backdropFilter: 'blur(5px)', position: 'fixed', left: anchor.x, top: anchor.y }}>
|
||||
return show ? <Box sx={{ zIndex: 1400, p: 1, background: 'rgba(0, 0, 0, 0.75)', backdropFilter: 'blur(5px)', position: 'fixed', left: anchor.x, top: anchor.y }}>
|
||||
<List sx={{ p: 0, m: 0, display: 'flex', flexDirection: 'column' }}>
|
||||
{props.options.map((item, i) => {
|
||||
return item === 'divider' ? <Divider key={`ContextMenu_Divider_${i}_${item}`}/> :
|
||||
return item === 'divider' ? <Divider key={`ContextMenu_Divider_${i}_${item}`}/> :
|
||||
<Button color='inherit' key={`ContextMenu_Value_${i}_${item}`} onClick={() => {
|
||||
item.onClick();
|
||||
setShow(false);
|
||||
|
|
@ -62,4 +62,4 @@ function ContextMenu<T extends HTMLElement, >(props: ContextMenuProps<T>) {
|
|||
</Box> : <></>;
|
||||
}
|
||||
|
||||
export default ContextMenu;
|
||||
export default ContextMenu;
|
||||
|
|
|
|||
12
src/hooks/useStore.tsx
Normal file
12
src/hooks/useStore.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
import { StoreAction, StoreContext, StoreState } from '../provider/Store';
|
||||
|
||||
const useStore = () => {
|
||||
const context = React.useContext(StoreContext as unknown as React.Context<[StoreState, React.Dispatch<StoreAction<keyof StoreState>>]>);
|
||||
if (!context) {
|
||||
throw new Error('useStore must be used under Store');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export default useStore;
|
||||
Loading…
Reference in a new issue