Compare commits
6 Commits
13e38737fb
...
61387e9fd8
| Author | SHA1 | Date | |
|---|---|---|---|
| 61387e9fd8 | |||
| 1354383860 | |||
| 6f25be49ca | |||
| 5f4da5d13f | |||
| 24e0bcbf92 | |||
| 5e7169079c |
4
src/assets/spinner.svg
Normal file
4
src/assets/spinner.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg class="animate-spin h-6 w-6 dark:text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 400 B |
@@ -4,7 +4,6 @@ import genDownloadLink from "../functions/genDownloadLink"
|
|||||||
import { FileOpenerProps } from "../types/FileOpenerProps"
|
import { FileOpenerProps } from "../types/FileOpenerProps"
|
||||||
|
|
||||||
const AudioOpener: React.FC<FileOpenerProps> = (props) => {
|
const AudioOpener: React.FC<FileOpenerProps> = (props) => {
|
||||||
|
|
||||||
const audio = React.createRef<HTMLAudioElement>()
|
const audio = React.createRef<HTMLAudioElement>()
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import { ReactComponent as BreadcrumImage } from "./../assets/breadcrum.svg"
|
import { ReactComponent as BreadcrumImage } from "./../assets/breadcrum.svg"
|
||||||
|
|
||||||
interface Props{
|
interface Props{
|
||||||
@@ -19,6 +18,7 @@ const Breadcrum: React.FC<Props> = (props) => {
|
|||||||
Root
|
Root
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{parts.map((e,i,arr)=>{
|
{parts.map((e,i,arr)=>{
|
||||||
const last = i == arr.length - 1
|
const last = i == arr.length - 1
|
||||||
return <div key={e} className="inline-flex items-center cursor-pointer">
|
return <div key={e} className="inline-flex items-center cursor-pointer">
|
||||||
@@ -39,9 +39,4 @@ const Breadcrum: React.FC<Props> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Breadcrum.propTypes = {
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
onDirClick: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Breadcrum
|
export default Breadcrum
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CreateDirButton: React.FC<Props> = (props) => {
|
const CreateDirButton: React.FC<Props> = (props) => {
|
||||||
|
|
||||||
const [name,setName] = useState("")
|
const [name,setName] = useState("")
|
||||||
const [show,setShow] = useState(false)
|
const [show,setShow] = useState(false)
|
||||||
const input = useRef<HTMLInputElement>(null)
|
const input = useRef<HTMLInputElement>(null)
|
||||||
@@ -37,6 +36,7 @@ const CreateDirButton: React.FC<Props> = (props) => {
|
|||||||
setName("")
|
setName("")
|
||||||
setShow(false)
|
setShow(false)
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
className="bg-transparent dark:text-gray-300 outline-none mx-1 border-b"
|
className="bg-transparent dark:text-gray-300 outline-none mx-1 border-b"
|
||||||
type="text"
|
type="text"
|
||||||
@@ -48,15 +48,6 @@ const CreateDirButton: React.FC<Props> = (props) => {
|
|||||||
setName("")
|
setName("")
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* <button
|
|
||||||
onClick={()=>{
|
|
||||||
props.onPressed?.(name)
|
|
||||||
setName("")
|
|
||||||
setShow(false)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Create
|
|
||||||
</button> */}
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import { Directory } from "../generated/graphql"
|
import { Directory } from "../generated/graphql"
|
||||||
import { MdFolderOpen } from "react-icons/md"
|
import { MdFolderOpen } from "react-icons/md"
|
||||||
|
|
||||||
@@ -21,8 +20,4 @@ const DirectoryElement: React.FC<Props> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryElement.propTypes = {
|
|
||||||
dir: PropTypes.any.isRequired // TODO: maybe you can use the interface
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DirectoryElement
|
export default DirectoryElement
|
||||||
@@ -45,7 +45,6 @@ const DragAndDrop: React.FC<Props> = (props) => {
|
|||||||
props.onDrop?.()
|
props.onDrop?.()
|
||||||
if (event.dataTransfer?.files && event.dataTransfer.files.length > 0) {
|
if (event.dataTransfer?.files && event.dataTransfer.files.length > 0) {
|
||||||
props.handleDrop?.(event.dataTransfer.files)
|
props.handleDrop?.(event.dataTransfer.files)
|
||||||
// event.dataTransfer.clearData()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import Breadcrum from "./Breadcrum"
|
|||||||
import CreateDirButton from "./CreateDirButton"
|
import CreateDirButton from "./CreateDirButton"
|
||||||
import DragAndDrop from "./DragAndDrop"
|
import DragAndDrop from "./DragAndDrop"
|
||||||
import FileBrowserContextMenu, { Action, CONTEXT_MENU_DIR, CONTEXT_MENU_FILE } from "./FileBrowserContextMenu"
|
import FileBrowserContextMenu, { Action, CONTEXT_MENU_DIR, CONTEXT_MENU_FILE } from "./FileBrowserContextMenu"
|
||||||
import FileBrowserElement from "./FileBrowserElement"
|
|
||||||
import FileOpen from "./FileOpen"
|
import FileOpen from "./FileOpen"
|
||||||
import FileUploadButton from "./FileUploadButton"
|
import FileUploadButton from "./FileUploadButton"
|
||||||
|
import { ReactComponent as Spinner } from "./../assets/spinner.svg"
|
||||||
|
import FileBrowserList from "./FileBrowserList"
|
||||||
|
|
||||||
function uriToPath(pathname:string) {
|
function uriToPath(pathname:string) {
|
||||||
// strip the "/f" from e.g. "/f/dir1/dir2"
|
// strip the "/f" from e.g. "/f/dir1/dir2"
|
||||||
@@ -32,6 +33,8 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
|||||||
|
|
||||||
const [srcID,setSrcID] = useState("")
|
const [srcID,setSrcID] = useState("")
|
||||||
const [pasteAction,setPasteAction] = useState<Action>()
|
const [pasteAction,setPasteAction] = useState<Action>()
|
||||||
|
const [editID,setEditID] = useState("")
|
||||||
|
const [editEnable,setEditEnable] = useState(false)
|
||||||
|
|
||||||
const [deleteMutation] = useDeleteFileMutation()
|
const [deleteMutation] = useDeleteFileMutation()
|
||||||
const [copyMutation] = useCopyMutation()
|
const [copyMutation] = useCopyMutation()
|
||||||
@@ -64,24 +67,6 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
|||||||
refetchDir()
|
refetchDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
function openFileContextMenu(e: React.MouseEvent, id: string) {
|
|
||||||
e.preventDefault()
|
|
||||||
showFileContext(e,{
|
|
||||||
props:{
|
|
||||||
id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function openDirContextMenu(e: React.MouseEvent, id: string) {
|
|
||||||
e.preventDefault()
|
|
||||||
showDirContext(e,{
|
|
||||||
props:{
|
|
||||||
id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onContextSelect(action:Action, id: string) {
|
async function onContextSelect(action:Action, id: string) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case Action.FileDelete:
|
case Action.FileDelete:
|
||||||
@@ -111,6 +96,10 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
|||||||
case Action.FileDownload:
|
case Action.FileDownload:
|
||||||
downloadFile(genDownloadLink(id))
|
downloadFile(genDownloadLink(id))
|
||||||
break
|
break
|
||||||
|
case Action.FileRename:
|
||||||
|
setEditID(id)
|
||||||
|
setEditEnable(true)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -147,49 +136,51 @@ const FileBrowser: React.FC<RouteComponentProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<FileBrowserList
|
||||||
|
directorys={data?.directorys || []}
|
||||||
|
files={data?.files || []}
|
||||||
|
|
||||||
|
onDirClick={(e,path)=>{
|
||||||
|
props.history.push(pathToUri(path))
|
||||||
|
}}
|
||||||
|
|
||||||
|
onDirContext={(e,path)=>{
|
||||||
|
e.preventDefault()
|
||||||
|
showDirContext(e,{props:{id:path}})
|
||||||
|
}}
|
||||||
|
|
||||||
|
onFileClick={(e,id)=>{
|
||||||
|
setOpenFileId(id)
|
||||||
|
setShowFile(true)
|
||||||
|
}}
|
||||||
|
|
||||||
|
onFileContext={(e,id)=>{
|
||||||
|
e.preventDefault()
|
||||||
|
showFileContext(e,{props:{id}})
|
||||||
|
}}
|
||||||
|
|
||||||
|
editId={editID}
|
||||||
|
editEnable={editEnable}
|
||||||
|
|
||||||
|
onRenameDone={(id,changed,newName)=>{
|
||||||
|
setEditEnable(false)
|
||||||
|
if (changed){
|
||||||
|
console.debug("Changed: ",newName)
|
||||||
|
}else{
|
||||||
|
console.debug("Not changed")
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{loading &&
|
{loading &&
|
||||||
<div>Loading...</div> // TODO: center
|
<div className="flex justify-center mt-4">
|
||||||
|
<Spinner />
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
<table className="w-full">
|
|
||||||
<thead className="border-b-2 dark:border-gray-900">
|
|
||||||
<tr>
|
|
||||||
<th className="text-left">Name</th>
|
|
||||||
<th className="text-left">Last Modified</th>
|
|
||||||
<th className="text-left">Size</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="divide-y dark:divide-gray-900">
|
|
||||||
|
|
||||||
{ data?.directorys.map(v => (<FileBrowserElement
|
|
||||||
key={v?.id}
|
|
||||||
dir={v}
|
|
||||||
onClick={(dir)=>{
|
|
||||||
props.history.push(pathToUri(dir.id))
|
|
||||||
}}
|
|
||||||
onContextMenu={(e)=>{
|
|
||||||
openDirContextMenu(e,v.id)
|
|
||||||
}}
|
|
||||||
/>))}
|
|
||||||
|
|
||||||
{ data?.files.map(v => (<FileBrowserElement
|
|
||||||
key={v?.id}
|
|
||||||
file={v}
|
|
||||||
onClick={(file)=>{
|
|
||||||
setOpenFileId(file.id)
|
|
||||||
setShowFile(true)
|
|
||||||
}}
|
|
||||||
onContextMenu={(e)=>{
|
|
||||||
openFileContextMenu(e,v.id)
|
|
||||||
}}
|
|
||||||
/>))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
{<FileOpen id={openFileId} show={showFile} onCloseClick={()=>{
|
<FileOpen id={openFileId} show={showFile} onCloseClick={()=>{
|
||||||
setShowFile(false)
|
setShowFile(false)
|
||||||
}} />}
|
}} />
|
||||||
</DragAndDrop>
|
</DragAndDrop>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export enum Action {
|
|||||||
FilePaste,
|
FilePaste,
|
||||||
FileMove,
|
FileMove,
|
||||||
FileDownload,
|
FileDownload,
|
||||||
|
FileRename,
|
||||||
DirDelete
|
DirDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,7 +21,6 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const FileBrowserContextMenu: React.FC<Props> = (props) => {
|
const FileBrowserContextMenu: React.FC<Props> = (props) => {
|
||||||
|
|
||||||
function onClick({ props: itemProps, data }: ItemParams<{id:string}, Action>) {
|
function onClick({ props: itemProps, data }: ItemParams<{id:string}, Action>) {
|
||||||
if (itemProps?.id && data != null){
|
if (itemProps?.id && data != null){
|
||||||
props.onSelect?.(data,itemProps.id)
|
props.onSelect?.(data,itemProps.id)
|
||||||
@@ -33,6 +33,7 @@ const FileBrowserContextMenu: React.FC<Props> = (props) => {
|
|||||||
<Item onClick={onClick} data={Action.FileDelete} >Delete</Item>
|
<Item onClick={onClick} data={Action.FileDelete} >Delete</Item>
|
||||||
<Item onClick={onClick} data={Action.FileCopy} >Copy</Item>
|
<Item onClick={onClick} data={Action.FileCopy} >Copy</Item>
|
||||||
<Item onClick={onClick} data={Action.FileMove} >Move</Item>
|
<Item onClick={onClick} data={Action.FileMove} >Move</Item>
|
||||||
|
<Item onClick={onClick} data={Action.FileRename} >Rename</Item>
|
||||||
<Item onClick={onClick} data={Action.FileDownload} >Download</Item>
|
<Item onClick={onClick} data={Action.FileDownload} >Download</Item>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Item onClick={onClick} data={Action.FilePaste} disabled={!props.pasteActive}>Paste</Item>
|
<Item onClick={onClick} data={Action.FilePaste} disabled={!props.pasteActive}>Paste</Item>
|
||||||
|
|||||||
@@ -1,40 +1,43 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import { Directory, File } from "../generated/graphql"
|
import { Directory, File } from "../generated/graphql"
|
||||||
import DirectoryComponent from "./DirectoryElement"
|
import DirectoryComponent from "./DirectoryElement"
|
||||||
import FileElement from "./FileElement"
|
import FileElement from "./FileElement"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
file?: File | null
|
file?: File
|
||||||
dir?: Directory | null
|
dir?: Directory
|
||||||
onClick?: (data: File | Directory) => void
|
onClick?: (event: React.MouseEvent ,data: File | Directory) => void
|
||||||
onContextMenu?: (e:React.MouseEvent) => void
|
onContextMenu?: (e:React.MouseEvent) => void
|
||||||
|
edit: boolean
|
||||||
|
onRename?: (newName: string)=>void
|
||||||
|
onCancleRename?: ()=>void
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileBrowserElement: React.FC<Props> = (props) => {
|
const FileBrowserElement: React.FC<Props> = (props) => {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
className="hover:bg-gray-100 dark:hover:bg-gray-900 text-lg"
|
className="hover:bg-gray-100 dark:hover:bg-gray-900 text-lg"
|
||||||
onClick={()=>{
|
onClick={(e)=>{
|
||||||
if(props.file){
|
if(props.file){
|
||||||
props.onClick?.(props.file)
|
props.onClick?.(e,props.file)
|
||||||
}else if(props.dir){
|
}else if(props.dir){
|
||||||
props.onClick?.(props.dir)
|
props.onClick?.(e,props.dir)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
onContextMenu={(e)=>props.onContextMenu?.(e)}
|
onContextMenu={(e)=>props.onContextMenu?.(e)}
|
||||||
|
|
||||||
>
|
>
|
||||||
{(props.file) ? <FileElement file={props.file}/>:(props.dir)?<DirectoryComponent dir={props.dir} />:<></>}
|
{(props.file) ? <FileElement
|
||||||
|
edit={props.edit}
|
||||||
|
file={props.file}
|
||||||
|
onCancleRename={props.onCancleRename}
|
||||||
|
onRename={props.onRename}
|
||||||
|
/>:(props.dir)?<DirectoryComponent
|
||||||
|
dir={props.dir}
|
||||||
|
/>:<></>}
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowserElement.propTypes = {
|
|
||||||
dir: PropTypes.any,
|
|
||||||
file: PropTypes.any,
|
|
||||||
onClick: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FileBrowserElement
|
export default FileBrowserElement
|
||||||
80
src/components/FileBrowserList.tsx
Normal file
80
src/components/FileBrowserList.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { Directory, File } from "../generated/graphql"
|
||||||
|
import FileBrowserElement from "./FileBrowserElement"
|
||||||
|
|
||||||
|
interface Props{
|
||||||
|
directorys: Directory[]
|
||||||
|
files: File[]
|
||||||
|
|
||||||
|
onFileContext?: (event: React.MouseEvent, id: string)=>void
|
||||||
|
onDirContext?: (event: React.MouseEvent, path: string)=>void
|
||||||
|
onFileClick?: (event: React.MouseEvent,id: string)=>void
|
||||||
|
onDirClick?: (event: React.MouseEvent,path: string)=>void
|
||||||
|
|
||||||
|
editId: string
|
||||||
|
editEnable: boolean
|
||||||
|
onRenameDone?: (id: string, changed: boolean, newName: string)=>void
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileBrowserList: React.FC<Props> = (props) => {
|
||||||
|
return <>
|
||||||
|
<table className="w-full">
|
||||||
|
<thead className="border-b-2 dark:border-gray-900">
|
||||||
|
<tr>
|
||||||
|
<th className="text-left">Name</th>
|
||||||
|
<th className="text-left">Last Modified</th>
|
||||||
|
<th className="text-left">Size</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y dark:divide-gray-900">
|
||||||
|
{ props.directorys.map(v => (<FileBrowserElement
|
||||||
|
key={v.id}
|
||||||
|
dir={v}
|
||||||
|
onClick={(e,dir)=>{
|
||||||
|
props.onDirClick?.(e,dir.id)
|
||||||
|
}}
|
||||||
|
onContextMenu={(e)=>{
|
||||||
|
props.onDirContext?.(e,v.id)
|
||||||
|
}}
|
||||||
|
|
||||||
|
edit={props.editEnable && (v.id === props.editId)}
|
||||||
|
|
||||||
|
onRename={(newName)=>{
|
||||||
|
if (v.name != newName){
|
||||||
|
props.onRenameDone?.(v.id,true,newName)
|
||||||
|
}else{
|
||||||
|
props.onRenameDone?.(v.id,false,newName)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
onCancleRename={()=>props.onRenameDone?.(v.id,false,"")}
|
||||||
|
/>))}
|
||||||
|
|
||||||
|
{ props.files.map(v => (<FileBrowserElement
|
||||||
|
key={v.id}
|
||||||
|
file={v}
|
||||||
|
onClick={(e,file)=>{
|
||||||
|
props.onFileClick?.(e,file.id)
|
||||||
|
}}
|
||||||
|
onContextMenu={(e)=>{
|
||||||
|
props.onFileContext?.(e,v.id)
|
||||||
|
}}
|
||||||
|
|
||||||
|
edit={props.editEnable && (v.id === props.editId)}
|
||||||
|
|
||||||
|
onRename={(newName)=>{
|
||||||
|
if (v.name != newName){
|
||||||
|
props.onRenameDone?.(v.id,true,newName)
|
||||||
|
}else{
|
||||||
|
props.onRenameDone?.(v.id,false,newName)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
onCancleRename={()=>props.onRenameDone?.(v.id,false,"")}
|
||||||
|
/>))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FileBrowserList
|
||||||
@@ -1,19 +1,28 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import { File } from "../generated/graphql"
|
import { File } from "../generated/graphql"
|
||||||
import sizeToReadable from "../functions/sizeToReadable"
|
import sizeToReadable from "../functions/sizeToReadable"
|
||||||
import dateFormat from "../functions/dateFomat"
|
import dateFormat from "../functions/dateFomat"
|
||||||
import { FaRegFileAlt } from "react-icons/fa"
|
import { FaRegFileAlt } from "react-icons/fa"
|
||||||
|
import Renameable from "./Renameable"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
file: File
|
file: File,
|
||||||
|
edit: boolean
|
||||||
|
onRename?: (newName: string)=>void
|
||||||
|
onCancleRename?: ()=>void
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileElement: React.FC<Props> = (props) => {
|
const FileElement: React.FC<Props> = (props) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<td>
|
<td>
|
||||||
<FaRegFileAlt className="inline" /> {props.file.name}
|
<FaRegFileAlt className="inline" />
|
||||||
|
<Renameable
|
||||||
|
text={props.file.name || ""}
|
||||||
|
edit={props.edit}
|
||||||
|
onCancleRename={props.onCancleRename}
|
||||||
|
onRename={props.onRename}
|
||||||
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{dateFormat(props.file.lastModified)}
|
{dateFormat(props.file.lastModified)}
|
||||||
@@ -26,8 +35,4 @@ const FileElement: React.FC<Props> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
FileElement.propTypes = {
|
|
||||||
file: PropTypes.any.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FileElement
|
export default FileElement
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import { useGetFileQuery } from "../generated/graphql"
|
import { useGetFileQuery } from "../generated/graphql"
|
||||||
import ImageOpener from "./ImageOpener"
|
import ImageOpener from "./ImageOpener"
|
||||||
import TextOpener from "./TextOpener"
|
import TextOpener from "./TextOpener"
|
||||||
@@ -13,7 +12,6 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const FileOpen: React.FC<Props> = (props) => {
|
const FileOpen: React.FC<Props> = (props) => {
|
||||||
|
|
||||||
if (!props.id) {
|
if (!props.id) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
@@ -66,10 +64,4 @@ const FileOpen: React.FC<Props> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
FileOpen.propTypes = {
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
show: PropTypes.bool.isRequired,
|
|
||||||
onCloseClick: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FileOpen
|
export default FileOpen
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const FileUploadButton: React.FC<Props> = (props) => {
|
const FileUploadButton: React.FC<Props> = (props) => {
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null)
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import genDownloadLink from "../functions/genDownloadLink"
|
import genDownloadLink from "../functions/genDownloadLink"
|
||||||
import { FileOpenerProps } from "../types/FileOpenerProps"
|
import { FileOpenerProps } from "../types/FileOpenerProps"
|
||||||
|
|
||||||
@@ -9,8 +8,4 @@ const ImageOpener: React.FC<FileOpenerProps> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageOpener.propTypes = {
|
|
||||||
file: PropTypes.any.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ImageOpener
|
export default ImageOpener
|
||||||
|
|||||||
51
src/components/Renameable.tsx
Normal file
51
src/components/Renameable.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
import { useRef } from "react"
|
||||||
|
import { useState } from "react"
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
text: string
|
||||||
|
edit: boolean
|
||||||
|
onRename?: (newName: string)=>void
|
||||||
|
onCancleRename?: ()=>void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Renameable: React.FC<Props> = (props) => {
|
||||||
|
const [inputValue,setinputValue] = useState(props.text)
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if (props.edit){
|
||||||
|
const i = inputValue.lastIndexOf(".")
|
||||||
|
inputRef.current?.select()
|
||||||
|
inputRef.current?.setSelectionRange(0,i == -1?inputValue.length:i)
|
||||||
|
}else{
|
||||||
|
setinputValue(props.text)
|
||||||
|
}
|
||||||
|
},[props.edit])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{props.edit && <form className="inline" onSubmit={(e)=>{
|
||||||
|
e.preventDefault()
|
||||||
|
props.onRename?.(inputValue)
|
||||||
|
}}>
|
||||||
|
<input
|
||||||
|
className="bg-transparent dark:text-gray-300 outline-none inline"
|
||||||
|
type="text"
|
||||||
|
ref={inputRef}
|
||||||
|
value={inputValue}
|
||||||
|
onClick={(e)=>e.stopPropagation()}
|
||||||
|
onChange={(e)=>{setinputValue(e.target.value)}}
|
||||||
|
onBlur={props.onCancleRename}
|
||||||
|
/></form>
|
||||||
|
|
||||||
|
}
|
||||||
|
{!props.edit &&
|
||||||
|
<div className="inline">{props.text}</div>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Renameable
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
|
||||||
import { FileOpenerProps } from "../types/FileOpenerProps"
|
import { FileOpenerProps } from "../types/FileOpenerProps"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
@@ -23,8 +22,4 @@ const TextOpener: React.FC<FileOpenerProps> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
TextOpener.propTypes = {
|
|
||||||
file: PropTypes.any.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TextOpener
|
export default TextOpener
|
||||||
|
|||||||
Reference in New Issue
Block a user