mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-22 02:12:30 +01:00
lint
This commit is contained in:
parent
e64e0fb216
commit
799333f898
@ -7,7 +7,6 @@ module.exports = {
|
||||
'jsx-a11y/control-has-associated-label': 0,
|
||||
'unicorn/prefer-node-protocol': 0, // todo
|
||||
'@typescript-eslint/no-var-requires': 0, // todo
|
||||
'react/display-name': 0, // todo
|
||||
},
|
||||
|
||||
overrides: [
|
||||
|
@ -5,7 +5,8 @@ import { FaTrashAlt, FaSave } from 'react-icons/fa';
|
||||
import { mySpring } from './animations';
|
||||
import { saveColor } from './colors';
|
||||
|
||||
const BetweenSegments = memo(({ start, end, duration, invertCutSegments }: { start: number, end: number, duration: number, invertCutSegments: boolean }) => {
|
||||
|
||||
function BetweenSegments({ start, end, duration, invertCutSegments }: { start: number, end: number, duration: number, invertCutSegments: boolean }) {
|
||||
const left = `${(start / duration) * 100}%`;
|
||||
|
||||
return (
|
||||
@ -38,6 +39,6 @@ const BetweenSegments = memo(({ start, end, duration, invertCutSegments }: { sta
|
||||
<div style={{ flexGrow: 1, borderBottom: '1px dashed var(--gray10)', marginLeft: 5, marginRight: 5 }} />
|
||||
</motion.div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default BetweenSegments;
|
||||
export default memo(BetweenSegments);
|
||||
|
@ -31,6 +31,7 @@ const zoomOptions = Array.from({ length: 13 }).fill().map((unused, z) => 2 ** z)
|
||||
|
||||
const leftRightWidth = 100;
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const InvertCutModeButton = memo(({ invertCutSegments, setInvertCutSegments }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -63,6 +64,7 @@ const InvertCutModeButton = memo(({ invertCutSegments, setInvertCutSegments }) =
|
||||
});
|
||||
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const CutTimeInput = memo(({ darkMode, cutTime, setCutTime, startTimeOffset, seekAbs, currentCutSeg, currentApparentCutSeg, isStart, formatTimecode, parseTimecode }) => {
|
||||
const { t } = useTranslation();
|
||||
const { getSegColor } = useSegColors();
|
||||
@ -166,7 +168,7 @@ const CutTimeInput = memo(({ darkMode, cutTime, setCutTime, startTimeOffset, see
|
||||
);
|
||||
});
|
||||
|
||||
const BottomBar = memo(({
|
||||
function BottomBar({
|
||||
zoom, setZoom, timelineToggleComfortZoom,
|
||||
isRotationSet, rotation, areWeCutting, increaseRotation, cleanupFilesDialog,
|
||||
captureSnapshot, onExportPress, segmentsToExport, hasVideo,
|
||||
@ -179,7 +181,7 @@ const BottomBar = memo(({
|
||||
toggleShowThumbnails, toggleWaveformMode, waveformMode, showThumbnails,
|
||||
outputPlaybackRate, setOutputPlaybackRate,
|
||||
formatTimecode, parseTimecode,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
@ -458,6 +460,6 @@ const BottomBar = memo(({
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default BottomBar;
|
||||
export default memo(BottomBar);
|
||||
|
@ -5,9 +5,9 @@ import CopyClipboardButton from './components/CopyClipboardButton';
|
||||
import Sheet from './components/Sheet';
|
||||
import { FfmpegCommandLog } from './types';
|
||||
|
||||
const LastCommandsSheet = memo(({ visible, onTogglePress, ffmpegCommandLog }: {
|
||||
function LastCommandsSheet({ visible, onTogglePress, ffmpegCommandLog }: {
|
||||
visible: boolean, onTogglePress: () => void, ffmpegCommandLog: FfmpegCommandLog,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -28,6 +28,6 @@ const LastCommandsSheet = memo(({ visible, onTogglePress, ffmpegCommandLog }: {
|
||||
)}
|
||||
</Sheet>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default LastCommandsSheet;
|
||||
export default memo(LastCommandsSheet);
|
||||
|
@ -8,9 +8,9 @@ import useUserSettings from './hooks/useUserSettings';
|
||||
|
||||
const electron = window.require('electron');
|
||||
|
||||
const NoFileLoaded = memo(({ mifiLink, currentCutSeg, onClick, darkMode }: {
|
||||
function NoFileLoaded({ mifiLink, currentCutSeg, onClick, darkMode }: {
|
||||
mifiLink: unknown, currentCutSeg, onClick: () => void, darkMode?: boolean,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { simpleMode } = useUserSettings();
|
||||
|
||||
@ -48,6 +48,6 @@ const NoFileLoaded = memo(({ mifiLink, currentCutSeg, onClick, darkMode }: {
|
||||
) : undefined}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default NoFileLoaded;
|
||||
export default memo(NoFileLoaded);
|
||||
|
@ -26,6 +26,7 @@ const buttonBaseStyle = {
|
||||
|
||||
const neutralButtonColor = 'var(--gray8)';
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const Segment = memo(({
|
||||
seg,
|
||||
index,
|
||||
@ -218,7 +219,7 @@ const Segment = memo(({
|
||||
);
|
||||
});
|
||||
|
||||
const SegmentList = memo(({
|
||||
function SegmentList({
|
||||
width,
|
||||
formatTimecode,
|
||||
apparentCutSegments,
|
||||
@ -294,7 +295,7 @@ const SegmentList = memo(({
|
||||
setEditingSegmentTags: Dispatch<SetStateAction<SegmentTags | undefined>>,
|
||||
setEditingSegmentTagsSegmentIndex: Dispatch<SetStateAction<number | undefined>>,
|
||||
onEditSegmentTags: (index: number) => void,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
@ -502,6 +503,6 @@ const SegmentList = memo(({
|
||||
</motion.div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default SegmentList;
|
||||
export default memo(SegmentList);
|
||||
|
@ -28,6 +28,7 @@ interface EditingStream {
|
||||
path: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const EditFileDialog = memo(({ editingFile, allFilesMeta, customTagsByFile, setCustomTagsByFile, editingTag, setEditingTag }: {
|
||||
editingFile: string, allFilesMeta: FilesMeta, customTagsByFile: CustomTagsByFile, setCustomTagsByFile: Dispatch<SetStateAction<CustomTagsByFile>>, editingTag: string | undefined, setEditingTag: (tag: string | undefined) => void
|
||||
}) => {
|
||||
@ -92,6 +93,7 @@ function StreamParametersEditor({ stream, streamParams, updateStreamParams }: {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const EditStreamDialog = memo(({ editingStream: { streamId: editingStreamId, path: editingFile }, setEditingStream, allFilesMeta, paramsByStreamId, updateStreamParams }: {
|
||||
editingStream: EditingStream, setEditingStream: Dispatch<SetStateAction<EditingStream | undefined>>, allFilesMeta: FilesMeta, paramsByStreamId: ParamsByStreamId, updateStreamParams: UpdateStreamParams,
|
||||
}) => {
|
||||
@ -149,6 +151,7 @@ function onInfoClick(json: unknown, title: string) {
|
||||
showJson5Dialog({ title, json });
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const Stream = memo(({ filePath, stream, onToggle, batchSetCopyStreamIds, copyStream, fileDuration, setEditingStream, onExtractStreamPress, paramsByStreamId, updateStreamParams, formatTimecode, loadSubtitleTrackToSegments }: {
|
||||
filePath: string, stream: FFprobeStream, onToggle: (a: number) => void, batchSetCopyStreamIds: (filter: (a: FFprobeStream) => boolean, enabled: boolean) => void, copyStream: boolean, fileDuration: number | undefined, setEditingStream: (a: EditingStream) => void, onExtractStreamPress?: () => void, paramsByStreamId: ParamsByStreamId, updateStreamParams: UpdateStreamParams, formatTimecode: FormatTimecode, loadSubtitleTrackToSegments?: (index: number) => void,
|
||||
}) => {
|
||||
|
@ -20,6 +20,7 @@ type CalculateTimelinePercent = (time: number) => string | undefined;
|
||||
|
||||
const currentTimeWidth = 1;
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const Waveform = memo(({ waveform, calculateTimelinePercent, durationSafe }: {
|
||||
waveform: RenderableWaveform, calculateTimelinePercent: CalculateTimelinePercent, durationSafe: number,
|
||||
}) => {
|
||||
@ -43,6 +44,7 @@ const Waveform = memo(({ waveform, calculateTimelinePercent, durationSafe }: {
|
||||
);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const Waveforms = memo(({ calculateTimelinePercent, durationSafe, waveforms, zoom, height }: {
|
||||
calculateTimelinePercent: CalculateTimelinePercent, durationSafe: number, waveforms: RenderableWaveform[], zoom: number, height: number,
|
||||
}) => (
|
||||
@ -53,6 +55,7 @@ const Waveforms = memo(({ calculateTimelinePercent, durationSafe, waveforms, zoo
|
||||
</div>
|
||||
));
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const CommandedTime = memo(({ commandedTimePercent }: { commandedTimePercent: string }) => {
|
||||
const color = 'var(--gray12)';
|
||||
const commonStyle: CSSProperties = { left: commandedTimePercent, position: 'absolute', pointerEvents: 'none' };
|
||||
@ -70,7 +73,7 @@ const timelineHeight = 36;
|
||||
const timeWrapperStyle: CSSProperties = { position: 'absolute', height: timelineHeight, left: 0, right: 0, bottom: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none' };
|
||||
const timeStyle: CSSProperties = { background: 'rgba(0,0,0,0.4)', borderRadius: 3, padding: '2px 4px', color: 'rgba(255, 255, 255, 0.8)' };
|
||||
|
||||
const Timeline = memo(({
|
||||
function Timeline({
|
||||
durationSafe,
|
||||
startTimeOffset,
|
||||
playerTime,
|
||||
@ -126,7 +129,7 @@ const Timeline = memo(({
|
||||
commandedTimeRef: MutableRefObject<number>,
|
||||
goToTimecode: () => void,
|
||||
isSegmentSelected: (a: { segId: string }) => boolean,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { invertCutSegments } = useUserSettings();
|
||||
@ -405,6 +408,6 @@ const Timeline = memo(({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default Timeline;
|
||||
export default memo(Timeline);
|
||||
|
@ -8,11 +8,11 @@ import { useSegColors } from './contexts';
|
||||
import { ApparentCutSegment, FormatTimecode } from './types';
|
||||
|
||||
|
||||
const TimelineSeg = memo(({
|
||||
function TimelineSeg({
|
||||
seg, duration, isActive, segNum, onSegClick, invertCutSegments, formatTimecode, selected,
|
||||
} : {
|
||||
seg: ApparentCutSegment, duration: number, isActive: boolean, segNum: number, onSegClick: (a: number) => void, invertCutSegments: boolean, formatTimecode: FormatTimecode, selected: boolean,
|
||||
}) => {
|
||||
}) {
|
||||
const { darkMode } = useUserSettings();
|
||||
const { getSegColor } = useSegColors();
|
||||
|
||||
@ -103,6 +103,6 @@ const TimelineSeg = memo(({
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
</motion.div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default TimelineSeg;
|
||||
export default memo(TimelineSeg);
|
||||
|
@ -16,7 +16,7 @@ import { InverseCutSegment } from './types';
|
||||
const outFmtStyle = { height: 20, maxWidth: 100 };
|
||||
const exportModeStyle = { flexGrow: 0, flexBasis: 140 };
|
||||
|
||||
const TopMenu = memo(({
|
||||
function TopMenu({
|
||||
filePath,
|
||||
fileFormat,
|
||||
copyAnyAudioTrack,
|
||||
@ -42,7 +42,7 @@ const TopMenu = memo(({
|
||||
selectedSegments: InverseCutSegment[],
|
||||
isCustomFormatSelected: boolean,
|
||||
clearOutDir: () => void,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { customOutDir, changeOutDir, simpleMode, outFormatLocked, setOutFormatLocked } = useUserSettings();
|
||||
|
||||
@ -113,6 +113,6 @@ const TopMenu = memo(({
|
||||
<IoIosSettings size={24} role="button" onClick={toggleSettings} style={{ marginLeft: 5 }} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default TopMenu;
|
||||
export default memo(TopMenu);
|
||||
|
@ -4,7 +4,7 @@ import { Button, ForkIcon, DisableIcon } from 'evergreen-ui';
|
||||
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
|
||||
const AutoExportToggler = memo(() => {
|
||||
function AutoExportToggler() {
|
||||
const { t } = useTranslation();
|
||||
const { autoExportExtraStreams, setAutoExportExtraStreams } = useUserSettings();
|
||||
|
||||
@ -13,6 +13,6 @@ const AutoExportToggler = memo(() => {
|
||||
{autoExportExtraStreams ? t('Extract') : t('Discard')}
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default AutoExportToggler;
|
||||
export default memo(AutoExportToggler);
|
||||
|
@ -5,9 +5,9 @@ import { FaAngleRight, FaFile } from 'react-icons/fa';
|
||||
import useContextMenu from '../hooks/useContextMenu';
|
||||
import { primaryTextColor } from '../colors';
|
||||
|
||||
const BatchFile = memo(({ path, isOpen, isSelected, name, onSelect, onDelete }: {
|
||||
function BatchFile({ path, isOpen, isSelected, name, onSelect, onDelete }: {
|
||||
path: string, isOpen: boolean, isSelected: boolean, name: string, onSelect: (a: string) => void, onDelete: (a: string) => void
|
||||
}) => {
|
||||
}) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { t } = useTranslation();
|
||||
@ -26,6 +26,6 @@ const BatchFile = memo(({ path, isOpen, isSelected, name, onSelect, onDelete }:
|
||||
{isOpen && <FaAngleRight size={14} style={{ color: 'var(--gray9)', marginRight: -5, flexShrink: 0 }} />}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default BatchFile;
|
||||
export default memo(BatchFile);
|
||||
|
@ -20,10 +20,10 @@ const iconStyle = {
|
||||
padding: '3px 5px',
|
||||
};
|
||||
|
||||
const BatchFilesList = memo(({ selectedBatchFiles, filePath, width, batchFiles, setBatchFiles, onBatchFileSelect, batchListRemoveFile, closeBatch, onMergeFilesClick, onBatchConvertToSupportedFormatClick }) => {
|
||||
function BatchFilesList({ selectedBatchFiles, filePath, width, batchFiles, setBatchFiles, onBatchFileSelect, batchListRemoveFile, closeBatch, onMergeFilesClick, onBatchConvertToSupportedFormatClick }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [sortDesc, setSortDesc] = useState();
|
||||
const [sortDesc, setSortDesc] = useState<boolean>();
|
||||
|
||||
const sortableList = batchFiles.map((batchFile) => ({ id: batchFile.path, batchFile }));
|
||||
|
||||
@ -70,6 +70,6 @@ const BatchFilesList = memo(({ selectedBatchFiles, filePath, width, batchFiles,
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default BatchFilesList;
|
||||
export default memo(BatchFilesList);
|
@ -5,9 +5,9 @@ import { ffmpegExtractWindow } from '../util/constants';
|
||||
import { RenderableWaveform } from '../types';
|
||||
|
||||
|
||||
const BigWaveform = memo(({ waveforms, relevantTime, playing, durationSafe, zoom, seekRel }: {
|
||||
function BigWaveform({ waveforms, relevantTime, playing, durationSafe, zoom, seekRel }: {
|
||||
waveforms: RenderableWaveform[], relevantTime: number, playing: boolean, durationSafe: number, zoom: number, seekRel: (a: number) => void,
|
||||
}) => {
|
||||
}) {
|
||||
const windowSize = ffmpegExtractWindow * 2;
|
||||
const windowStart = Math.max(0, relevantTime - windowSize);
|
||||
const windowEnd = relevantTime + windowSize;
|
||||
@ -129,6 +129,6 @@ const BigWaveform = memo(({ waveforms, relevantTime, playing, durationSafe, zoom
|
||||
<div style={{ pointerEvents: 'none', position: 'absolute', height: '100%', backgroundColor: 'var(--red11)', width: 1, left: '50%', top: 0 }} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default BigWaveform;
|
||||
export default memo(BigWaveform);
|
||||
|
@ -2,9 +2,11 @@ import { ButtonHTMLAttributes, memo } from 'react';
|
||||
|
||||
import styles from './Button.module.css';
|
||||
|
||||
const Button = memo(({ type = 'button', ...props }: ButtonHTMLAttributes<HTMLButtonElement>) => (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading, react/button-has-type
|
||||
<button className={styles['button']} type={type} {...props} />
|
||||
));
|
||||
function Button({ type = 'button', ...props }: ButtonHTMLAttributes<HTMLButtonElement>) {
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading, react/button-has-type
|
||||
<button className={styles['button']} type={type} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export default Button;
|
||||
export default memo(Button);
|
||||
|
@ -6,7 +6,8 @@ import { FaImage } from 'react-icons/fa';
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
import { withBlur } from '../util';
|
||||
|
||||
const CaptureFormatButton = memo(({ showIcon = false, ...props }: { showIcon?: boolean } & ButtonProps) => {
|
||||
|
||||
function CaptureFormatButton({ showIcon = false, ...props }: { showIcon?: boolean } & ButtonProps) {
|
||||
const { t } = useTranslation();
|
||||
const { captureFormat, toggleCaptureFormat } = useUserSettings();
|
||||
return (
|
||||
@ -20,6 +21,6 @@ const CaptureFormatButton = memo(({ showIcon = false, ...props }: { showIcon?: b
|
||||
{captureFormat}
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default CaptureFormatButton;
|
||||
export default memo(CaptureFormatButton);
|
||||
|
@ -26,9 +26,9 @@ const rowStyle: CSSProperties = {
|
||||
color: 'black', fontSize: 14, margin: '4px 0px', overflowY: 'auto', whiteSpace: 'nowrap',
|
||||
};
|
||||
|
||||
const ConcatDialog = memo(({ isShown, onHide, paths, onConcat, alwaysConcatMultipleFiles, setAlwaysConcatMultipleFiles }: {
|
||||
function ConcatDialog({ isShown, onHide, paths, onConcat, alwaysConcatMultipleFiles, setAlwaysConcatMultipleFiles }: {
|
||||
isShown: boolean, onHide: () => void, paths: string[], onConcat: (a: { paths: string[], includeAllStreams: boolean, streams: FFprobeStream[], outFileName: string, fileFormat: string, clearBatchFilesAfterConcat: boolean }) => Promise<void>, alwaysConcatMultipleFiles: boolean, setAlwaysConcatMultipleFiles: (a: boolean) => void,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { preserveMovData, setPreserveMovData, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge } = useUserSettings();
|
||||
|
||||
@ -238,6 +238,6 @@ const ConcatDialog = memo(({ isShown, onHide, paths, onConcat, alwaysConcatMulti
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ConcatDialog;
|
||||
export default memo(ConcatDialog);
|
||||
|
@ -6,7 +6,7 @@ import { MotionStyle, motion, useAnimation } from 'framer-motion';
|
||||
const electron = window.require('electron');
|
||||
const { clipboard } = electron;
|
||||
|
||||
const CopyClipboardButton = memo(({ text, style }: { text: string, style?: MotionStyle }) => {
|
||||
function CopyClipboardButton({ text, style }: { text: string, style?: MotionStyle }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const animation = useAnimation();
|
||||
@ -24,6 +24,6 @@ const CopyClipboardButton = memo(({ text, style }: { text: string, style?: Motio
|
||||
<FaClipboard title={t('Copy to clipboard')} onClick={onClick} />
|
||||
</motion.span>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default CopyClipboardButton;
|
||||
export default memo(CopyClipboardButton);
|
||||
|
@ -8,9 +8,9 @@ import useUserSettings from '../hooks/useUserSettings';
|
||||
import { SegmentToExport } from '../types';
|
||||
|
||||
|
||||
const ExportButton = memo(({ segmentsToExport, areWeCutting, onClick, size = 1 }: {
|
||||
function ExportButton({ segmentsToExport, areWeCutting, onClick, size = 1 }: {
|
||||
segmentsToExport: SegmentToExport[], areWeCutting: boolean, onClick: () => void, size?: number | undefined,
|
||||
}) => {
|
||||
}) {
|
||||
const CutIcon = areWeCutting ? FiScissors : FaFileExport;
|
||||
|
||||
const { t } = useTranslation();
|
||||
@ -40,6 +40,6 @@ const ExportButton = memo(({ segmentsToExport, areWeCutting, onClick, size = 1 }
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ExportButton;
|
||||
export default memo(ExportButton);
|
||||
|
@ -39,7 +39,7 @@ const warningStyle: CSSProperties = { color: 'var(--orange8)', fontSize: '80%',
|
||||
|
||||
const HelpIcon = ({ onClick, style }: { onClick: () => void, style?: CSSProperties }) => <IoIosHelpCircle size={20} role="button" onClick={withBlur(onClick)} style={{ cursor: 'pointer', color: primaryTextColor, verticalAlign: 'middle', ...style }} />;
|
||||
|
||||
const ExportConfirm = memo(({
|
||||
function ExportConfirm({
|
||||
areWeCutting,
|
||||
selectedSegments,
|
||||
segmentsToExport,
|
||||
@ -89,7 +89,7 @@ const ExportConfirm = memo(({
|
||||
setMergedOutFileName: (a: string) => void,
|
||||
smartCutBitrate: number | undefined,
|
||||
setSmartCutBitrate: Dispatch<SetStateAction<number | undefined>>,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { changeOutDir, keyframeCut, toggleKeyframeCut, preserveMovData, movFastStart, avoidNegativeTs, setAvoidNegativeTs, autoDeleteMergedSegments, exportConfirmEnabled, toggleExportConfirmEnabled, segmentsToChapters, toggleSegmentsToChapters, preserveMetadataOnMerge, togglePreserveMetadataOnMerge, enableSmartCut, setEnableSmartCut, effectiveExportMode, enableOverwriteOutput, setEnableOverwriteOutput, ffmpegExperimental, setFfmpegExperimental, cutFromAdjustmentFrames, setCutFromAdjustmentFrames } = useUserSettings();
|
||||
@ -539,6 +539,6 @@ const ExportConfirm = memo(({
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ExportConfirm;
|
||||
export default memo(ExportConfirm);
|
||||
|
@ -7,7 +7,7 @@ import Select from './Select';
|
||||
import { ExportMode } from '../types';
|
||||
|
||||
|
||||
const ExportModeButton = memo(({ selectedSegments, style }: { selectedSegments: unknown[], style?: CSSProperties }) => {
|
||||
function ExportModeButton({ selectedSegments, style }: { selectedSegments: unknown[], style?: CSSProperties }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { effectiveExportMode, setAutoMerge, setAutoDeleteMergedSegments, setSegmentsToChaptersOnly } = useUserSettings();
|
||||
@ -75,6 +75,6 @@ const ExportModeButton = memo(({ selectedSegments, style }: { selectedSegments:
|
||||
})}
|
||||
</Select>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ExportModeButton;
|
||||
export default memo(ExportModeButton);
|
||||
|
@ -44,6 +44,7 @@ function fixKeys(keys: string[]) {
|
||||
return orderBy(uniqed, [(key) => key !== 'shift', (key) => key !== 'ctrl', (key) => key !== 'alt', (key) => key !== 'meta', (key) => key]);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const CreateBinding = memo(({
|
||||
actionsMap, action, setCreatingBinding, onNewKeyBindingConfirmed,
|
||||
}: {
|
||||
@ -117,6 +118,7 @@ const CreateBinding = memo(({
|
||||
|
||||
const rowStyle = { display: 'flex', alignItems: 'center', margin: '.2em 0', borderBottom: '1px solid rgba(0,0,0,0.1)', paddingBottom: '.5em' };
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const KeyboardShortcuts = memo(({
|
||||
keyBindings, setKeyBindings, resetKeyBindings, currentCutSeg,
|
||||
}: {
|
||||
@ -775,11 +777,11 @@ const KeyboardShortcuts = memo(({
|
||||
);
|
||||
});
|
||||
|
||||
const KeyboardShortcutsDialog = memo(({
|
||||
function KeyboardShortcutsDialog({
|
||||
isShown, onHide, keyBindings, setKeyBindings, resetKeyBindings, currentCutSeg,
|
||||
}: {
|
||||
isShown: boolean, onHide: () => void, keyBindings: KeyBinding[], setKeyBindings: Dispatch<SetStateAction<KeyBinding[]>>, resetKeyBindings: () => void, currentCutSeg: StateSegment,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -795,6 +797,6 @@ const KeyboardShortcutsDialog = memo(({
|
||||
{isShown ? <KeyboardShortcuts keyBindings={keyBindings} setKeyBindings={setKeyBindings} currentCutSeg={currentCutSeg} resetKeyBindings={resetKeyBindings} /> : <div />}
|
||||
</Dialog>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default KeyboardShortcutsDialog;
|
||||
export default memo(KeyboardShortcutsDialog);
|
||||
|
@ -3,10 +3,12 @@ import { memo } from 'react';
|
||||
import TextInput from './TextInput';
|
||||
|
||||
|
||||
const MergedOutFileName = memo(({ mergedOutFileName, setMergedOutFileName }: { mergedOutFileName: string | undefined, setMergedOutFileName: (a: string) => void }) => (
|
||||
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'flex-end' }}>
|
||||
<TextInput value={mergedOutFileName ?? ''} onChange={(e) => setMergedOutFileName(e.target.value)} style={{ textAlign: 'right' }} />
|
||||
</div>
|
||||
));
|
||||
function MergedOutFileName({ mergedOutFileName, setMergedOutFileName }: { mergedOutFileName: string | undefined, setMergedOutFileName: (a: string) => void }) {
|
||||
return (
|
||||
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'flex-end' }}>
|
||||
<TextInput value={mergedOutFileName ?? ''} onChange={(e) => setMergedOutFileName(e.target.value)} style={{ textAlign: 'right' }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MergedOutFileName;
|
||||
export default memo(MergedOutFileName);
|
||||
|
@ -5,12 +5,12 @@ import useUserSettings from '../hooks/useUserSettings';
|
||||
import Switch from './Switch';
|
||||
|
||||
|
||||
const MovFastStartButton = memo(() => {
|
||||
function MovFastStartButton() {
|
||||
const { movFastStart, toggleMovFastStart } = useUserSettings();
|
||||
|
||||
return (
|
||||
<Switch checked={movFastStart} onCheckedChange={withBlur(toggleMovFastStart)} />
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default MovFastStartButton;
|
||||
export default memo(MovFastStartButton);
|
@ -23,9 +23,9 @@ const formatVariable = (variable) => `\${${variable}}`;
|
||||
|
||||
const extVar = formatVariable('EXT');
|
||||
|
||||
const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generateOutSegFileNames, currentSegIndexSafe }: {
|
||||
function OutSegTemplateEditor({ outSegTemplate, setOutSegTemplate, generateOutSegFileNames, currentSegIndexSafe }: {
|
||||
outSegTemplate: string, setOutSegTemplate: (text: string) => void, generateOutSegFileNames: GenerateOutSegFileNames, currentSegIndexSafe: number,
|
||||
}) => {
|
||||
}) {
|
||||
const { safeOutputFileName, toggleSafeOutputFileName, outputFileNameMinZeroPadding, setOutputFileNameMinZeroPadding } = useUserSettings();
|
||||
|
||||
const [text, setText] = useState(outSegTemplate);
|
||||
@ -174,6 +174,6 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default OutSegTemplateEditor;
|
||||
export default memo(OutSegTemplateEditor);
|
||||
|
@ -9,15 +9,15 @@ const commonVideoAudioFormats = ['matroska', 'mov', 'mp4', 'mpegts', 'ogv', 'web
|
||||
const commonAudioFormats = ['flac', 'ipod', 'mp3', 'oga', 'ogg', 'opus', 'wav'];
|
||||
const commonSubtitleFormats = ['ass', 'srt', 'sup', 'webvtt'];
|
||||
|
||||
function renderFormatOptions(formats) {
|
||||
function renderFormatOptions(formats: string[]) {
|
||||
return formats.map((format) => (
|
||||
<option key={format} value={format}>{format} - {allOutFormats[format]}</option>
|
||||
));
|
||||
}
|
||||
|
||||
const OutputFormatSelect = memo(({ style, detectedFileFormat, fileFormat, onOutputFormatUserChange }: {
|
||||
function OutputFormatSelect({ style, detectedFileFormat, fileFormat, onOutputFormatUserChange }: {
|
||||
style: CSSProperties, detectedFileFormat?: string | undefined, fileFormat?: string | undefined, onOutputFormatUserChange: (a: string) => void,
|
||||
}) => {
|
||||
}) {
|
||||
const commonVideoAudioFormatsExceptDetectedFormat = useMemo(() => commonVideoAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);
|
||||
const commonAudioFormatsExceptDetectedFormat = useMemo(() => commonAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);
|
||||
const commonSubtitleFormatsExceptDetectedFormat = useMemo(() => commonSubtitleFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);
|
||||
@ -49,6 +49,6 @@ const OutputFormatSelect = memo(({ style, detectedFileFormat, fileFormat, onOutp
|
||||
{renderFormatOptions(otherFormats)}
|
||||
</Select>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default OutputFormatSelect;
|
||||
export default memo(OutputFormatSelect);
|
||||
|
@ -3,7 +3,7 @@ import { MdSubtitles } from 'react-icons/md';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Select from './Select';
|
||||
|
||||
const PlaybackStreamSelector = memo(({
|
||||
function PlaybackStreamSelector({
|
||||
subtitleStreams,
|
||||
videoStreams,
|
||||
audioStreams,
|
||||
@ -23,7 +23,7 @@ const PlaybackStreamSelector = memo(({
|
||||
onActiveSubtitleChange: (a?: number | undefined) => void,
|
||||
onActiveVideoStreamChange: (a?: number | undefined) => void,
|
||||
onActiveAudioStreamChange: (a?: number | undefined) => void,
|
||||
}) => {
|
||||
}) {
|
||||
const [controlVisible, setControlVisible] = useState(false);
|
||||
const timeoutRef = useRef<number>();
|
||||
|
||||
@ -105,6 +105,6 @@ const PlaybackStreamSelector = memo(({
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default PlaybackStreamSelector;
|
||||
export default memo(PlaybackStreamSelector);
|
||||
|
@ -5,12 +5,12 @@ import useUserSettings from '../hooks/useUserSettings';
|
||||
import Switch from './Switch';
|
||||
|
||||
|
||||
const PreserveMovDataButton = memo(() => {
|
||||
function PreserveMovDataButton() {
|
||||
const { preserveMovData, togglePreserveMovData } = useUserSettings();
|
||||
|
||||
return (
|
||||
<Switch checked={preserveMovData} onCheckedChange={withBlur(togglePreserveMovData)} />
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default PreserveMovDataButton;
|
||||
export default memo(PreserveMovDataButton);
|
@ -2,9 +2,12 @@ import { SelectHTMLAttributes, memo } from 'react';
|
||||
|
||||
import styles from './Select.module.css';
|
||||
|
||||
const Select = memo((props: SelectHTMLAttributes<HTMLSelectElement>) => (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
<select className={styles['select']} {...props} />
|
||||
));
|
||||
|
||||
export default Select;
|
||||
function Select(props: SelectHTMLAttributes<HTMLSelectElement>) {
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
<select className={styles['select']} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(Select);
|
||||
|
@ -41,7 +41,7 @@ const Header = ({ title }: { title: string }) => (
|
||||
|
||||
const detailsStyle: CSSProperties = { opacity: 0.75, fontSize: '.9em', marginTop: '.3em' };
|
||||
|
||||
const Settings = memo(({
|
||||
function Settings({
|
||||
onTunerRequested,
|
||||
onKeyboardShortcutsDialogRequested,
|
||||
askForCleanupChoices,
|
||||
@ -55,7 +55,7 @@ const Settings = memo(({
|
||||
toggleStoreProjectInWorkingDir: () => Promise<void>,
|
||||
simpleMode: boolean,
|
||||
clearOutDir: () => Promise<void>,
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [showAdvanced, setShowAdvanced] = useState(!simpleMode);
|
||||
|
||||
@ -481,6 +481,6 @@ const Settings = memo(({
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default Settings;
|
||||
export default memo(Settings);
|
||||
|
@ -5,9 +5,10 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import styles from './Sheet.module.css';
|
||||
|
||||
const Sheet = memo(({ visible, onClosePress, children, maxWidth = 800, style }: {
|
||||
|
||||
function Sheet({ visible, onClosePress, children, maxWidth = 800, style }: {
|
||||
visible: boolean, onClosePress: () => void, children: ReactNode, maxWidth?: number, style?: CSSProperties
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -30,6 +31,6 @@ const Sheet = memo(({ visible, onClosePress, children, maxWidth = 800, style }:
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default Sheet;
|
||||
export default memo(Sheet);
|
||||
|
@ -6,7 +6,7 @@ import { primaryTextColor } from '../colors';
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
|
||||
|
||||
const SimpleModeButton = memo(({ size = 20, style }: { size?: number, style: CSSProperties }) => {
|
||||
function SimpleModeButton({ size = 20, style }: { size?: number, style: CSSProperties }) {
|
||||
const { t } = useTranslation();
|
||||
const { simpleMode, toggleSimpleMode } = useUserSettings();
|
||||
|
||||
@ -18,6 +18,6 @@ const SimpleModeButton = memo(({ size = 20, style }: { size?: number, style: CSS
|
||||
onClick={toggleSimpleMode}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default SimpleModeButton;
|
||||
export default memo(SimpleModeButton);
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { CSSProperties, forwardRef } from 'react';
|
||||
|
||||
|
||||
const inputStyle: CSSProperties = { borderRadius: '.4em', flexGrow: 1, fontFamily: 'inherit', fontSize: '.8em', backgroundColor: 'var(--gray3)', color: 'var(--gray12)', border: '1px solid var(--gray7)', appearance: 'none' };
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const TextInput = forwardRef<HTMLInputElement, JSX.IntrinsicElements['input']>(({ style, ...props }, forwardedRef) => (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
<input type="text" ref={forwardedRef} style={{ ...inputStyle, ...style }} {...props} />
|
||||
|
@ -7,13 +7,13 @@ import { primaryTextColor } from '../colors';
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
|
||||
|
||||
const ToggleExportConfirm = memo(({ size = 23, style }: { size?: number | undefined, style?: CSSProperties }) => {
|
||||
function ToggleExportConfirm({ size = 23, style }: { size?: number | undefined, style?: CSSProperties }) {
|
||||
const { t } = useTranslation();
|
||||
const { exportConfirmEnabled, toggleExportConfirmEnabled } = useUserSettings();
|
||||
|
||||
return (
|
||||
<MdEventNote style={{ color: exportConfirmEnabled ? primaryTextColor : 'var(--gray11)', ...style }} size={size} title={t('Show export options screen before exporting?')} role="button" onClick={toggleExportConfirmEnabled} />
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ToggleExportConfirm;
|
||||
export default memo(ToggleExportConfirm);
|
||||
|
@ -5,9 +5,9 @@ import { useTranslation } from 'react-i18next';
|
||||
import Switch from './Switch';
|
||||
|
||||
|
||||
const ValueTuner = memo(({ style, title, value, setValue, onFinished, resolution = 1000, min: minIn = 0, max: maxIn = 1, resetToDefault }: {
|
||||
function ValueTuner({ style, title, value, setValue, onFinished, resolution = 1000, min: minIn = 0, max: maxIn = 1, resetToDefault }: {
|
||||
style?: CSSProperties, title: string, value: number, setValue: (string) => void, onFinished: () => void, resolution?: number, min?: number, max?: number, resetToDefault: () => void
|
||||
}) => {
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [min, setMin] = useState(minIn);
|
||||
@ -49,6 +49,6 @@ const ValueTuner = memo(({ style, title, value, setValue, onFinished, resolution
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ValueTuner;
|
||||
export default memo(ValueTuner);
|
||||
|
@ -5,7 +5,8 @@ import ValueTuner from './ValueTuner';
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
import { TunerType } from '../types';
|
||||
|
||||
const ValueTuners = memo(({ type, onFinished }: { type: TunerType, onFinished: () => void }) => {
|
||||
|
||||
function ValueTuners({ type, onFinished }: { type: TunerType, onFinished: () => void }) {
|
||||
const { t } = useTranslation();
|
||||
const { wheelSensitivity, setWheelSensitivity, keyboardNormalSeekSpeed, keyboardSeekSpeed2, setKeyboardSeekSpeed2, keyboardSeekSpeed3, setKeyboardSeekSpeed3, setKeyboardNormalSeekSpeed, keyboardSeekAccFactor, setKeyboardSeekAccFactor } = useUserSettings();
|
||||
|
||||
@ -57,7 +58,7 @@ const ValueTuners = memo(({ type, onFinished }: { type: TunerType, onFinished: (
|
||||
const resetToDefault = () => setValue(defaultValue);
|
||||
|
||||
return <ValueTuner title={title} value={value} setValue={setValue} onFinished={onFinished} max={max} min={min} resetToDefault={resetToDefault} />;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export default ValueTuners;
|
||||
export default memo(ValueTuners);
|
||||
|
@ -3,7 +3,7 @@ import { FaVolumeMute, FaVolumeUp } from 'react-icons/fa';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
||||
const VolumeControl = memo(({ playbackVolume, setPlaybackVolume }: { playbackVolume: number, setPlaybackVolume: (a: number) => void }) => {
|
||||
function VolumeControl({ playbackVolume, setPlaybackVolume }: { playbackVolume: number, setPlaybackVolume: (a: number) => void }) {
|
||||
const [volumeControlVisible, setVolumeControlVisible] = useState(false);
|
||||
const timeoutRef = useRef<number>();
|
||||
const { t } = useTranslation();
|
||||
@ -52,6 +52,6 @@ const VolumeControl = memo(({ playbackVolume, setPlaybackVolume }: { playbackVol
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default VolumeControl;
|
||||
export default memo(VolumeControl);
|
||||
|
@ -8,40 +8,42 @@ import { primaryColor } from '../colors';
|
||||
import loadingLottie from '../7077-magic-flow.json';
|
||||
|
||||
|
||||
const Working = memo(({ text, cutProgress, onAbortClick }: {
|
||||
function Working({ text, cutProgress, onAbortClick }: {
|
||||
text: string, cutProgress?: number | undefined, onAbortClick: () => void
|
||||
}) => (
|
||||
<div style={{ position: 'absolute', bottom: 0, top: 0, left: 0, right: 0, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<motion.div
|
||||
style={{ background: primaryColor, boxShadow: `${primaryColor} 0px 0px 20px 25px`, borderRadius: 60, paddingBottom: 5, color: 'white', fontSize: 14, display: 'flex', flexDirection: 'column', alignItems: 'center' }}
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0 }}
|
||||
>
|
||||
<div style={{ width: 150, height: 80 }}>
|
||||
<Lottie
|
||||
loop
|
||||
animationData={loadingLottie}
|
||||
play
|
||||
style={{ width: '170%', height: '210%', marginLeft: '-40%', marginTop: '-35%', pointerEvents: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 5 }}>
|
||||
{text}...
|
||||
</div>
|
||||
|
||||
{(cutProgress != null) && (
|
||||
<div style={{ marginTop: 5 }}>
|
||||
{`${(cutProgress * 100).toFixed(1)} %`}
|
||||
}) {
|
||||
return (
|
||||
<div style={{ position: 'absolute', bottom: 0, top: 0, left: 0, right: 0, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<motion.div
|
||||
style={{ background: primaryColor, boxShadow: `${primaryColor} 0px 0px 20px 25px`, borderRadius: 60, paddingBottom: 5, color: 'white', fontSize: 14, display: 'flex', flexDirection: 'column', alignItems: 'center' }}
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0 }}
|
||||
>
|
||||
<div style={{ width: 150, height: 80 }}>
|
||||
<Lottie
|
||||
loop
|
||||
animationData={loadingLottie}
|
||||
play
|
||||
style={{ width: '170%', height: '210%', marginLeft: '-40%', marginTop: '-35%', pointerEvents: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: 5 }}>
|
||||
<Button intent="danger" onClick={onAbortClick} height={20}><Trans>Abort</Trans></Button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
));
|
||||
<div style={{ marginTop: 5 }}>
|
||||
{text}...
|
||||
</div>
|
||||
|
||||
export default Working;
|
||||
{(cutProgress != null) && (
|
||||
<div style={{ marginTop: 5 }}>
|
||||
{`${(cutProgress * 100).toFixed(1)} %`}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: 5 }}>
|
||||
<Button intent="danger" onClick={onAbortClick} height={20}><Trans>Abort</Trans></Button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(Working);
|
||||
|
Loading…
Reference in New Issue
Block a user