feat: add website and folder upload and download (#260)
* feat: add website and folder upload and download * feat: download-share-upload navigation * fix: check for files length in hasIndexDocument * fix: change router dependency * refactor: switch to @ethersphere/manfest-js * fix: hide previews on dropzone, fix spinner align, hide 0 size display * feat: add upload and download history * refactor: change drag and drop text * feat: make history ux better * refactor: improve code based on review * build: add missing react-router dependency * ci: remove beeload * revert(ci): remove beeload This reverts commit 4ce6cb0045a2d9aea3047ab395d214d8d368c532.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { Grid, IconButton, ListItem, Tooltip, Typography } from '@material-ui/core'
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import { OpenInNewSharp } from '@material-ui/icons'
|
||||
import { ArrowForward, OpenInNewSharp } from '@material-ui/icons'
|
||||
import { ReactElement, useState } from 'react'
|
||||
import CopyToClipboard from 'react-copy-to-clipboard'
|
||||
import { useHistory } from 'react-router'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -46,15 +47,35 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
interface Props {
|
||||
label: string
|
||||
value: string
|
||||
link?: string
|
||||
navigationType?: 'NEW_WINDOW' | 'HISTORY_PUSH'
|
||||
allowClipboard?: boolean
|
||||
}
|
||||
|
||||
export default function ExpandableListItemLink({ label, value }: Props): ReactElement | null {
|
||||
export default function ExpandableListItemLink({
|
||||
label,
|
||||
value,
|
||||
link,
|
||||
navigationType = 'NEW_WINDOW',
|
||||
allowClipboard = true,
|
||||
}: Props): ReactElement | null {
|
||||
const classes = useStyles()
|
||||
const [copied, setCopied] = useState(false)
|
||||
const history = useHistory()
|
||||
|
||||
const tooltipClickHandler = () => setCopied(true)
|
||||
const tooltipCloseHandler = () => setCopied(false)
|
||||
|
||||
const displayValue = value.length > 22 ? value.slice(0, 19) + '...' : value
|
||||
|
||||
function onNavigation() {
|
||||
if (navigationType === 'NEW_WINDOW') {
|
||||
window.open(link || value)
|
||||
} else {
|
||||
history.push(link || value)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ListItem className={classes.header}>
|
||||
<Grid container direction="column" justifyContent="space-between" alignItems="stretch">
|
||||
@@ -62,15 +83,19 @@ export default function ExpandableListItemLink({ label, value }: Props): ReactEl
|
||||
{label && <Typography variant="body1">{label}</Typography>}
|
||||
<Typography variant="body2">
|
||||
<div>
|
||||
<span className={classes.copyValue}>
|
||||
<Tooltip title={copied ? 'Copied' : 'Copy'} placement="top" arrow onClose={tooltipCloseHandler}>
|
||||
<CopyToClipboard text={value}>
|
||||
<span onClick={tooltipClickHandler}>{value.slice(0, 19)}...</span>
|
||||
</CopyToClipboard>
|
||||
</Tooltip>
|
||||
</span>
|
||||
{allowClipboard && (
|
||||
<span className={classes.copyValue}>
|
||||
<Tooltip title={copied ? 'Copied' : 'Copy'} placement="top" arrow onClose={tooltipCloseHandler}>
|
||||
<CopyToClipboard text={value}>
|
||||
<span onClick={tooltipClickHandler}>{displayValue}</span>
|
||||
</CopyToClipboard>
|
||||
</Tooltip>
|
||||
</span>
|
||||
)}
|
||||
{!allowClipboard && <span onClick={onNavigation}>{displayValue}</span>}
|
||||
<IconButton size="small" className={classes.openLinkIcon}>
|
||||
<OpenInNewSharp onClick={() => window.open(value)} strokeWidth={1} />
|
||||
{navigationType === 'NEW_WINDOW' && <OpenInNewSharp onClick={onNavigation} strokeWidth={1} />}
|
||||
{navigationType === 'HISTORY_PUSH' && <ArrowForward onClick={onNavigation} strokeWidth={1} />}
|
||||
</IconButton>
|
||||
</div>
|
||||
</Typography>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { ReactElement, useEffect, useState } from 'react'
|
||||
import { getPrettyDateString } from '../utils/date'
|
||||
import { getHistorySafe, HistoryItem, HISTORY_KEYS } from '../utils/local-storage'
|
||||
import ExpandableList from './ExpandableList'
|
||||
import ExpandableListItemLink from './ExpandableListItemLink'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
localStorageKey: HISTORY_KEYS
|
||||
}
|
||||
|
||||
export function History({ title, localStorageKey }: Props): ReactElement | null {
|
||||
const [items, setItems] = useState<HistoryItem[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
setItems(getHistorySafe(localStorageKey))
|
||||
}, [localStorageKey])
|
||||
|
||||
if (!items.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<ExpandableList label={title} defaultOpen>
|
||||
{items.map((x, i) => (
|
||||
<ExpandableListItemLink
|
||||
label={getPrettyDateString(new Date(x.createdAt))}
|
||||
value={x.name}
|
||||
link={'/files/hash/' + x.hash}
|
||||
key={i}
|
||||
navigationType="HISTORY_PUSH"
|
||||
allowClipboard={false}
|
||||
/>
|
||||
))}
|
||||
</ExpandableList>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Box, createStyles, Grid, makeStyles, Typography } from '@material-ui/core'
|
||||
import { ArrowBack } from '@material-ui/icons'
|
||||
import { ReactElement } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
interface Props {
|
||||
children: string
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
pressable: {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
icon: {
|
||||
color: '#242424',
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export function HistoryHeader({ children }: Props): ReactElement {
|
||||
const classes = useStyles()
|
||||
const history = useHistory()
|
||||
|
||||
function goBack() {
|
||||
history.goBack()
|
||||
}
|
||||
|
||||
return (
|
||||
<Box mb={4}>
|
||||
<Grid container direction="row">
|
||||
<Box mr={2}>
|
||||
<div className={classes.pressable} onClick={goBack}>
|
||||
<ArrowBack className={classes.icon} />
|
||||
</div>
|
||||
</Box>
|
||||
<Typography variant="h1">{children}</Typography>
|
||||
</Grid>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { CircularProgress, Grid } from '@material-ui/core'
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
export function Loading(): ReactElement {
|
||||
return (
|
||||
<Grid container direction="row" justifyContent="center" alignItems="center">
|
||||
<CircularProgress />
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import { createStyles, Theme, makeStyles } from '@material-ui/core/styles'
|
||||
import { Divider, Drawer, Grid, Link as MUILink, List } from '@material-ui/core'
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import { OpenInNewSharp } from '@material-ui/icons'
|
||||
import { Divider, List, Drawer, Grid, Link as MUILink } from '@material-ui/core'
|
||||
import { Home, FileText, DollarSign, Settings, Layers, BookOpen } from 'react-feather'
|
||||
import type { ReactElement } from 'react'
|
||||
import { BookOpen, DollarSign, FileText, Home, Layers, Settings } from 'react-feather'
|
||||
import { Link } from 'react-router-dom'
|
||||
import Logo from '../assets/logo.svg'
|
||||
import { ROUTES } from '../routes'
|
||||
import SideBarItem from './SideBarItem'
|
||||
import SideBarStatus from './SideBarStatus'
|
||||
|
||||
import Logo from '../assets/logo.svg'
|
||||
|
||||
const navBarItems = [
|
||||
{
|
||||
label: 'Info',
|
||||
@@ -19,7 +17,7 @@ const navBarItems = [
|
||||
},
|
||||
{
|
||||
label: 'Files',
|
||||
path: ROUTES.FILES,
|
||||
path: ROUTES.UPLOAD,
|
||||
icon: FileText,
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user