diff --git a/app/src/components/FileBrowser.js b/app/src/components/FileBrowser.js index d69f2150..d43bc1c1 100644 --- a/app/src/components/FileBrowser.js +++ b/app/src/components/FileBrowser.js @@ -1,17 +1,20 @@ -import {Button, Header, Icon, Modal, Placeholder, Progress, Segment, Table} from "./Theme"; import { + ActionInput, + Button, Checkbox, - Form, - Grid, - IconGroup, - Input, - PlaceholderLine, - TableBody, - TableCell, - TableHeader, - TableHeaderCell, - TableRow -} from "semantic-ui-react"; + Header, + Icon, + IconButton, + IconStack, + Modal, + Panel, + Placeholder, + Progress, + Skeleton, + Stack, + Table, + TextInput, +} from "./ui"; import { APIButton, DirectorySearch, @@ -23,6 +26,7 @@ import { useIsIgnoredDirectory } from "./Common"; import React, {useContext, useEffect, useState} from "react"; +import {IconArrowsMove, IconChevronsUp, IconCursorText, IconTags} from "@tabler/icons-react"; import {useDropzone} from "react-dropzone"; import {useHotkeys} from "react-hotkeys-hook"; import {deleteFile, ignoreDirectory, makeDirectory, movePaths, renamePath, unignoreDirectory} from "../api"; @@ -111,23 +115,28 @@ function Folder({folder, onFolderClick, sortData, onFileClick, disabled, loading const isLoading = loadingFolders && loadingFolders.has(path); const depth = (path.match(/\//g) || []).length; - const f = handleDragStart(path, e)} onMouseEnter={() => handleDragMove(path)} > - + onSelect(folder['path'])}/> - - shouldAllowClick() && onFolderClick(path)} className='file-path' colSpan={2} disabled={is_empty}> + + shouldAllowClick() && onFolderClick(path)} + className='file-path' + colSpan={2} + style={is_empty ? {opacity: 0.5} : undefined} + > {depthIndentation(pathWithNoTrailingSlash)} {is_empty ? : } {ignored && } {name} - - ; + + ; if (children) { // Folder has children, recursively display them. children = sortData(children); @@ -164,27 +173,27 @@ function File({file, onFileClick, disabled}) { const showAsSelected = (isInSelectedPaths && !isDragDeselecting) || isDragSelecting; // Visual highlight class const dragClass = isDragSelecting ? 'drag-selecting' : (isDragDeselecting ? 'drag-deselecting' : ''); - return handleDragStart(path, e)} onMouseEnter={() => handleDragMove(path)} > - + onSelect(path)}/> - - shouldAllowClick() && onFileClick(file)} className='file-path'> + + shouldAllowClick() && onFileClick(file)} className='file-path'> {depthIndentation(path)} {/*null size to make icon the correct size*/} {pathName(path)} - - + + {humanFileSize(size)} - - + + } function Path({path, onFolderClick, onFileClick, sortData, disabled, loadingFolders}) { @@ -209,17 +218,15 @@ function Path({path, onFolderClick, onFileClick, sortData, disabled, loadingFold function SkeletonFileRow({depth}) { const indentation = '\xa0\xa0\xa0\xa0'.repeat(depth); return ( - - + + - - + + {indentation} - - - - - + + + ); } @@ -387,28 +394,26 @@ export function FileBrowser() { const [footerRef, footerWidth] = useElementWidth(); // Expand icon-only buttons to include labels once the footer is wide enough to fit them. const showLabels = footerWidth >= FOOTER_LABELS_MIN_WIDTH; - // Semantic UI renders a labeled icon button when `content` and `labelPosition` are set, else icon-only. - const labelProps = (content) => showLabels ? {content, labelPosition: 'left'} : {}; + // Show a label alongside the icon once there's room; otherwise the icon carries the meaning alone. + const label = (text) => showLabels ? text : null; const footerClassName = `sticky-footer ${inverted}`; const footer =
- {selectedPathsCount === 1 ? : null} - {selectedPathsCount > 0 ? setMoveOpen(false)} @@ -435,10 +439,9 @@ export function FileBrowser() { disabled={wrolModeEnabled} style={{paddingLeft: '1em', paddingRight: showLabels ? '1em' : '0.8em'}} > - + } label='New folder'> - - + {showLabels ? <> New Folder : null} 0 && !singleDirectorySelected)} onClick={() => setUploadOpen(true)} - {...labelProps('Upload')} - /> + >{label('Upload')} setUploadOpen(false)} @@ -465,8 +467,7 @@ export function FileBrowser() { icon={isDirectoryIgnored ? 'eye' : 'eye slash'} disabled={!singleDirectorySelected || wrolModeEnabled} onClick={() => setIgnoreDirectoryOpen(true)} - {...labelProps(isDirectoryIgnored ? 'Unignore' : 'Ignore')} - /> + >{label(isDirectoryIgnored ? 'Unignore' : 'Ignore')} setBulkTagOpen(false)} @@ -536,10 +536,7 @@ export function FileBrowser() { ); if (browseFiles === null) { - return - - - ; + return ; } else if (browseFiles === undefined) { return Could not fetch files } @@ -551,31 +548,29 @@ export function FileBrowser() { openFolders={openFolders} >
- } placeholder='Filter files...' value={filterStr} - onChange={(e, {value}) => setFilterStr(value)} + onChange={(e) => setFilterStr(e.target.value)} aria-label='Filter files' className='file-browser-filter' ref={filterInputRef} - action={
@@ -598,7 +593,6 @@ function FileBrowserContent({browseFiles, headers, onFolderClick, setPreviewFile return (
{ - if (e) { - e.preventDefault(); - } - setValue(props.value); + const handleInputChange = (e) => { + setValue(e.target.value); } const handleSubmit = async (e) => { @@ -652,25 +643,31 @@ export function RenameModal({open, onClose, path, onSubmit, onPending}) { setValue(pathName(path)); }, [path]); - return Rename: {name} -
+
New Name
{parent ? parent + '/' : null}{value}
- -
+
+ -
} @@ -710,47 +701,47 @@ export function MoveModal({open, paths, onClose, onSubmit}) { } } - const fileCell = i => + const fileCell = i =>
{i}
-
; + ; - const destinationRows = paths.map(i => + const destinationRows = paths.map(i => {fileCell(i)} {destination ? fileCell(destination + '/' + pathName(i)) : fileCell(pathName(i))} - ); + ); - return Move Files/Directories

Search for a directory to move your files into:

- + - - - Source - Destination - - - + + + Source + Destination + + + {destinationRows} - +
+ -
} @@ -779,20 +770,20 @@ export function IgnoreDirectoryModal({open, onClose, onSubmit, directory, ignore const content = ignored ? 'Remove ignore of the following directory? You must refresh your files after this.' : 'Ignore the following directory? The files within will not be indexed and will not show in search results.'; - let submitButton = ; - return + return {header} {content}
{mediaDirectory}/{directory}
+ {submitButton} -
} @@ -801,11 +792,8 @@ export function MakeDirectoryModal({open, onClose, parent, onSubmit}) { const [value, setValue] = useState(''); const mediaDirectory = useMediaDirectory(); - const handleInputChange = (e, props) => { - if (e) { - e.preventDefault(); - } - setValue(props.value); + const handleInputChange = (e) => { + setValue(e.target.value); } const handleSubmit = async (e) => { @@ -824,18 +812,18 @@ export function MakeDirectoryModal({open, onClose, parent, onSubmit}) { } } - return + return Make Directory -
+
{mediaDirectory}/{parent}{value}
- -
+
@@ -845,7 +833,6 @@ export function MakeDirectoryModal({open, onClose, parent, onSubmit}) { export function FileBrowserUploadModal({open, onClose, destination, onComplete}) { const mediaDirectory = useMediaDirectory(); - const {t} = React.useContext(ThemeContext); const { setFiles, @@ -909,27 +896,22 @@ export function FileBrowserUploadModal({open, onClose, destination, onComplete}) color = 'orange'; statusString = 'Already Exists:'; } - let indicating = status === 'pending'; - return - - - - - -

{statusString} {name}

-
-
-
+ return
+ +
+ +
+
}) } const displayPath = destination ? `${mediaDirectory}/${destination}` : mediaDirectory; - return + return Upload to: {displayPath} -
+ e.preventDefault()}> {tagsSelector}
-
+ - - - - -
-
- - - - -
- - Click here, or drop files here to upload -
-
-
-
-
-
-
-
-
-
+ +
+ +
Click here, or drop files here to upload
+
+
- - - - {progresses && Object.keys(progresses).length > 1 && } - - - - + {progresses && Object.keys(progresses).length > 1 && +
+ +
} + + {progressBars} -
+
- }> - + + + + + {SLICERS.map(s => - { - // Navigate programmatically so keyboard activation (which may not - // follow the href) still launches the slicer. - if (e) e.preventDefault(); - setSlicerKey(s.key); - window.location.assign(getSlicerURL(previewFile, s.scheme)); - }}/>)} - - - + { + // Navigate programmatically so keyboard activation (which may not + // follow the href) still launches the slicer. + if (e) e.preventDefault(); + setSlicerKey(s.key); + window.location.assign(getSlicerURL(previewFile, s.scheme)); + }} + > + Open in {s.text} + )} + + + } function getEpubViewerURL(previewFile) { @@ -115,7 +119,7 @@ function getImagePreviewModal(previewFile) { @@ -131,7 +135,7 @@ function getVideoPreviewModal(previewFile) { {name} - {path['path']} +
{path['path']}