2022-02-05 13:16:57 +00:00
|
|
|
import type { OdFolderChildren } from '../types'
|
2022-02-05 09:25:46 +00:00
|
|
|
|
|
|
|
import Link from 'next/link'
|
2022-02-05 13:16:57 +00:00
|
|
|
import { useState } from 'react'
|
2022-02-05 09:25:46 +00:00
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
2022-02-05 11:00:25 +00:00
|
|
|
import { useClipboard } from 'use-clipboard-copy'
|
2022-02-06 10:35:03 +00:00
|
|
|
import { useTranslation } from 'next-i18next'
|
2022-02-05 09:25:46 +00:00
|
|
|
|
2022-02-05 11:00:25 +00:00
|
|
|
import { getBaseUrl } from '../utils/getBaseUrl'
|
2022-02-05 09:25:46 +00:00
|
|
|
import { formatModifiedDateTime } from '../utils/fileDetails'
|
2022-02-07 18:54:48 +00:00
|
|
|
import { getReadablePath } from '../utils/getReadablePath'
|
2022-02-05 13:16:57 +00:00
|
|
|
import { Checkbox, ChildIcon, Downloading, formatChildName } from './FileListing'
|
2022-02-05 09:25:46 +00:00
|
|
|
|
|
|
|
const GridItem = ({ c }: { c: OdFolderChildren }) => {
|
|
|
|
// We use the generated medium thumbnail for rendering preview images
|
|
|
|
const thumbnail = c.thumbnails && c.thumbnails.length > 0 ? c.thumbnails[0].medium : null
|
|
|
|
|
2022-02-05 11:12:20 +00:00
|
|
|
// Some thumbnails are broken, so we check for onerror event in the image component
|
|
|
|
const [brokenThumbnail, setBrokenThumbnail] = useState(false)
|
|
|
|
|
2022-02-05 09:25:46 +00:00
|
|
|
return (
|
|
|
|
<div className="space-y-2">
|
2022-02-05 11:00:25 +00:00
|
|
|
<div className="h-32 overflow-hidden rounded border border-gray-900/10 dark:border-gray-500/30">
|
2022-02-05 11:12:20 +00:00
|
|
|
{thumbnail && !brokenThumbnail ? (
|
2022-02-05 09:25:46 +00:00
|
|
|
// eslint-disable-next-line @next/next/no-img-element
|
2022-02-05 11:12:20 +00:00
|
|
|
<img
|
|
|
|
className="h-full w-full object-cover object-top"
|
|
|
|
src={thumbnail.url}
|
|
|
|
alt={c.name}
|
|
|
|
onError={() => setBrokenThumbnail(true)}
|
|
|
|
/>
|
2022-02-05 09:25:46 +00:00
|
|
|
) : (
|
|
|
|
<div className="relative flex h-full w-full items-center justify-center rounded-lg">
|
2022-02-05 13:16:57 +00:00
|
|
|
<ChildIcon child={c} />
|
2022-02-05 09:25:46 +00:00
|
|
|
<span className="absolute bottom-0 right-0 m-1 font-medium text-gray-700 dark:text-gray-500">
|
|
|
|
{c.folder?.childCount}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="flex items-start justify-center space-x-2">
|
|
|
|
<span className="w-5 flex-shrink-0 text-center">
|
2022-02-05 13:16:57 +00:00
|
|
|
<ChildIcon child={c} />
|
2022-02-05 09:25:46 +00:00
|
|
|
</span>
|
2022-02-05 13:16:57 +00:00
|
|
|
<span className="overflow-hidden truncate">{formatChildName(c.name)}</span>
|
2022-02-05 09:25:46 +00:00
|
|
|
</div>
|
|
|
|
<div className="truncate text-center font-mono text-xs text-gray-700 dark:text-gray-500">
|
|
|
|
{formatModifiedDateTime(c.lastModifiedDateTime)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const FolderGridLayout = ({
|
|
|
|
path,
|
|
|
|
folderChildren,
|
|
|
|
selected,
|
|
|
|
toggleItemSelected,
|
|
|
|
totalSelected,
|
|
|
|
toggleTotalSelected,
|
|
|
|
totalGenerating,
|
|
|
|
handleSelectedDownload,
|
|
|
|
folderGenerating,
|
|
|
|
handleFolderDownload,
|
|
|
|
toast,
|
|
|
|
}) => {
|
2022-02-05 11:00:25 +00:00
|
|
|
const clipboard = useClipboard()
|
|
|
|
|
2022-02-06 10:35:03 +00:00
|
|
|
const { t } = useTranslation()
|
|
|
|
|
2022-02-05 09:25:46 +00:00
|
|
|
return (
|
2022-02-05 11:00:25 +00:00
|
|
|
<div className="rounded bg-white dark:bg-gray-900 dark:text-gray-100">
|
|
|
|
<div className="flex items-center border-b border-gray-900/10 px-3 text-xs font-bold uppercase tracking-widest text-gray-600 dark:border-gray-500/30 dark:text-gray-400">
|
2022-02-06 11:26:11 +00:00
|
|
|
<div className="flex-1">{t('{{count}} item(s)', { count: folderChildren.length })}</div>
|
2022-02-05 11:00:25 +00:00
|
|
|
<div className="flex p-1.5 text-gray-700 dark:text-gray-400">
|
|
|
|
<Checkbox
|
|
|
|
checked={totalSelected}
|
|
|
|
onChange={toggleTotalSelected}
|
|
|
|
indeterminate={true}
|
2022-02-06 10:35:03 +00:00
|
|
|
title={t('Select all files')}
|
2022-02-05 11:00:25 +00:00
|
|
|
/>
|
|
|
|
{totalGenerating ? (
|
2022-02-06 10:35:03 +00:00
|
|
|
<Downloading title={t('Downloading selected files, refresh page to cancel')} />
|
2022-02-05 11:00:25 +00:00
|
|
|
) : (
|
|
|
|
<button
|
2022-02-06 10:35:03 +00:00
|
|
|
title={t('Download selected files')}
|
2022-02-05 11:00:25 +00:00
|
|
|
className="cursor-pointer rounded p-1.5 hover:bg-gray-300 disabled:cursor-not-allowed disabled:text-gray-400 disabled:hover:bg-white dark:hover:bg-gray-600 disabled:dark:text-gray-600 disabled:hover:dark:bg-gray-900"
|
|
|
|
disabled={totalSelected === 0}
|
|
|
|
onClick={handleSelectedDownload}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'arrow-alt-circle-down']} size="lg" />
|
|
|
|
</button>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2022-02-05 11:05:13 +00:00
|
|
|
<div className="grid grid-cols-2 gap-3 p-3 md:grid-cols-4">
|
2022-02-05 11:00:25 +00:00
|
|
|
{folderChildren.map((c: OdFolderChildren) => (
|
2022-02-05 13:16:57 +00:00
|
|
|
<div
|
|
|
|
key={c.id}
|
|
|
|
className="group relative overflow-hidden rounded transition-all duration-100 hover:bg-gray-100 dark:hover:bg-gray-850"
|
|
|
|
>
|
|
|
|
<div className="absolute top-0 right-0 z-10 m-1 rounded bg-white/50 py-0.5 opacity-0 transition-all duration-100 group-hover:opacity-100 dark:bg-gray-900/50">
|
2022-02-05 11:05:13 +00:00
|
|
|
{c.folder ? (
|
|
|
|
<div>
|
|
|
|
<span
|
2022-02-06 10:35:03 +00:00
|
|
|
title={t('Copy folder permalink')}
|
2022-02-05 11:05:13 +00:00
|
|
|
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
|
|
|
|
onClick={() => {
|
2022-02-07 18:54:48 +00:00
|
|
|
clipboard.copy(
|
|
|
|
`${getBaseUrl()}${getReadablePath(`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`)}`
|
|
|
|
)
|
2022-02-06 10:35:03 +00:00
|
|
|
toast(t('Copied folder permalink.'), { icon: '👌' })
|
2022-02-05 11:05:13 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'copy']} />
|
|
|
|
</span>
|
|
|
|
{folderGenerating[c.id] ? (
|
2022-02-06 10:35:03 +00:00
|
|
|
<Downloading title={t('Downloading folder, refresh page to cancel')} />
|
2022-02-05 11:05:13 +00:00
|
|
|
) : (
|
2022-02-05 11:00:25 +00:00
|
|
|
<span
|
2022-02-06 10:35:03 +00:00
|
|
|
title={t('Download folder')}
|
2022-02-05 11:00:25 +00:00
|
|
|
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
|
|
|
|
onClick={() => {
|
2022-02-05 11:05:13 +00:00
|
|
|
const p = `${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`
|
|
|
|
handleFolderDownload(p, c.id, c.name)()
|
2022-02-05 11:00:25 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'arrow-alt-circle-down']} />
|
2022-02-05 11:05:13 +00:00
|
|
|
</span>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div>
|
|
|
|
<span
|
2022-02-06 10:35:03 +00:00
|
|
|
title={t('Copy raw file permalink')}
|
2022-02-05 11:05:13 +00:00
|
|
|
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
|
|
|
|
onClick={() => {
|
|
|
|
clipboard.copy(
|
2022-02-07 18:54:48 +00:00
|
|
|
`${getBaseUrl()}/api?path=${getReadablePath(
|
|
|
|
`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`
|
|
|
|
)}&raw=true`
|
2022-02-05 11:05:13 +00:00
|
|
|
)
|
2022-02-06 10:35:03 +00:00
|
|
|
toast.success(t('Copied raw file permalink.'))
|
2022-02-05 11:05:13 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'copy']} />
|
|
|
|
</span>
|
|
|
|
<a
|
2022-02-06 10:35:03 +00:00
|
|
|
title={t('Download file')}
|
2022-02-05 11:05:13 +00:00
|
|
|
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
|
|
|
|
href={c['@microsoft.graph.downloadUrl']}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'arrow-alt-circle-down']} />
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
2022-02-05 11:00:25 +00:00
|
|
|
|
2022-02-05 13:16:57 +00:00
|
|
|
<div
|
|
|
|
className={`${
|
|
|
|
selected[c.id] ? 'opacity-100' : 'opacity-0'
|
|
|
|
} absolute top-0 left-0 z-10 m-1 rounded bg-white/50 py-0.5 group-hover:opacity-100 dark:bg-gray-900/50`}
|
|
|
|
>
|
2022-02-05 11:05:13 +00:00
|
|
|
{!c.folder && !(c.name === '.password') && (
|
|
|
|
<Checkbox
|
|
|
|
checked={selected[c.id] ? 2 : 0}
|
|
|
|
onChange={() => toggleItemSelected(c.id)}
|
2022-02-06 10:35:03 +00:00
|
|
|
title={t('Select file')}
|
2022-02-05 11:05:13 +00:00
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</div>
|
2022-02-05 11:00:25 +00:00
|
|
|
|
2022-02-05 11:05:13 +00:00
|
|
|
<Link href={`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`} passHref>
|
|
|
|
<a>
|
|
|
|
<GridItem c={c} />
|
|
|
|
</a>
|
|
|
|
</Link>
|
|
|
|
</div>
|
2022-02-05 11:00:25 +00:00
|
|
|
))}
|
|
|
|
</div>
|
2022-02-05 09:25:46 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default FolderGridLayout
|