2021-06-23 20:27:51 +00:00
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
2021-06-25 17:47:57 +00:00
|
|
|
import toast, { Toaster } from 'react-hot-toast'
|
2021-06-30 12:09:37 +00:00
|
|
|
import emojiRegex from 'emoji-regex'
|
2021-08-23 14:02:06 +00:00
|
|
|
import { useClipboard } from 'use-clipboard-copy'
|
2021-06-23 20:27:51 +00:00
|
|
|
|
|
|
|
import { ParsedUrlQuery } from 'querystring'
|
2021-11-18 22:36:23 +00:00
|
|
|
import { FunctionComponent, useEffect, useRef, useState } from 'react'
|
2021-06-24 13:54:59 +00:00
|
|
|
import { ImageDecorator } from 'react-viewer/lib/ViewerProps'
|
2021-06-23 22:51:23 +00:00
|
|
|
|
|
|
|
import { useRouter } from 'next/router'
|
|
|
|
import dynamic from 'next/dynamic'
|
|
|
|
|
|
|
|
import { getExtension, getFileIcon, hasKey } from '../utils/getFileIcon'
|
|
|
|
import { extensions, preview } from '../utils/getPreviewType'
|
2021-11-18 23:28:05 +00:00
|
|
|
import { getBaseUrl, saveFiles, useProtectedSWRInfinite } from '../utils/tools'
|
2021-09-05 15:03:27 +00:00
|
|
|
|
2021-06-24 13:54:59 +00:00
|
|
|
import { VideoPreview } from './previews/VideoPreview'
|
|
|
|
import { AudioPreview } from './previews/AudioPreview'
|
2021-06-25 18:22:22 +00:00
|
|
|
import Loading from './Loading'
|
2021-06-25 14:15:00 +00:00
|
|
|
import FourOhFour from './FourOhFour'
|
2021-08-30 00:35:52 +00:00
|
|
|
import Auth from './Auth'
|
2021-06-25 14:15:00 +00:00
|
|
|
import TextPreview from './previews/TextPreview'
|
2021-06-25 15:08:04 +00:00
|
|
|
import MarkdownPreview from './previews/MarkdownPreview'
|
2021-06-25 15:13:31 +00:00
|
|
|
import CodePreview from './previews/CodePreview'
|
2021-06-29 15:20:35 +00:00
|
|
|
import OfficePreview from './previews/OfficePreview'
|
2021-06-29 20:00:05 +00:00
|
|
|
import DownloadBtn from './DownloadBtn'
|
2021-06-22 13:55:53 +00:00
|
|
|
|
2021-06-24 23:42:46 +00:00
|
|
|
// Disabling SSR for some previews (image gallery view, and PDF view)
|
2021-06-23 22:51:23 +00:00
|
|
|
const ReactViewer = dynamic(() => import('react-viewer'), { ssr: false })
|
2021-06-24 23:42:46 +00:00
|
|
|
const PDFPreview = dynamic(() => import('./previews/PDFPreview'), { ssr: false })
|
2021-10-05 21:28:40 +00:00
|
|
|
const EPUBPreview = dynamic(() => import('./previews/EPUBPreview'), { ssr: false })
|
2021-06-23 20:27:51 +00:00
|
|
|
|
2021-06-23 22:51:23 +00:00
|
|
|
/**
|
|
|
|
* Convert raw bits file/folder size into a human readable string
|
|
|
|
*
|
|
|
|
* @param size File or folder size, in raw bits
|
|
|
|
* @returns Human readable form of the file or folder size
|
|
|
|
*/
|
2021-06-22 23:15:19 +00:00
|
|
|
const humanFileSize = (size: number) => {
|
|
|
|
if (size < 1024) return size + ' B'
|
|
|
|
const i = Math.floor(Math.log(size) / Math.log(1024))
|
|
|
|
const num = size / Math.pow(1024, i)
|
|
|
|
const round = Math.round(num)
|
|
|
|
const formatted = round < 10 ? num.toFixed(2) : round < 100 ? num.toFixed(1) : round
|
|
|
|
return `${formatted} ${'KMGTPEZY'[i - 1]}B`
|
|
|
|
}
|
|
|
|
|
2021-06-24 13:54:59 +00:00
|
|
|
/**
|
|
|
|
* Convert url query into path string
|
|
|
|
*
|
|
|
|
* @param query Url query property
|
|
|
|
* @returns Path string
|
|
|
|
*/
|
2021-06-23 20:27:51 +00:00
|
|
|
const queryToPath = (query?: ParsedUrlQuery) => {
|
|
|
|
if (query) {
|
|
|
|
const { path } = query
|
|
|
|
if (!path) return '/'
|
2021-08-15 19:38:51 +00:00
|
|
|
if (typeof path === 'string') return `/${encodeURIComponent(path)}`
|
|
|
|
return `/${path.map(p => encodeURIComponent(p)).join('/')}`
|
2021-06-22 23:15:19 +00:00
|
|
|
}
|
2021-06-23 20:27:51 +00:00
|
|
|
return '/'
|
2021-06-22 23:15:19 +00:00
|
|
|
}
|
2021-06-22 13:55:53 +00:00
|
|
|
|
2021-06-23 22:51:23 +00:00
|
|
|
const FileListItem: FunctionComponent<{
|
|
|
|
fileContent: { id: string; name: string; size: number; file: Object; lastModifiedDateTime: string }
|
|
|
|
}> = ({ fileContent: c }) => {
|
2021-06-30 12:09:37 +00:00
|
|
|
const emojiIcon = emojiRegex().exec(c.name)
|
|
|
|
const renderEmoji = emojiIcon && !emojiIcon.index
|
|
|
|
|
2021-06-23 22:51:23 +00:00
|
|
|
return (
|
2021-11-18 20:13:19 +00:00
|
|
|
<div className="grid items-center grid-cols-10 p-3 space-x-2 cursor-pointer">
|
|
|
|
<div className="md:col-span-6 flex items-center col-span-10 space-x-2 truncate">
|
2021-06-23 22:51:23 +00:00
|
|
|
{/* <div>{c.file ? c.file.mimeType : 'folder'}</div> */}
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="flex-shrink-0 w-5 text-center">
|
2021-06-30 12:09:37 +00:00
|
|
|
{renderEmoji ? (
|
|
|
|
<span>{emojiIcon ? emojiIcon[0] : '📁'}</span>
|
|
|
|
) : (
|
|
|
|
<FontAwesomeIcon icon={c.file ? getFileIcon(c.name) : ['far', 'folder']} />
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
<div className="truncate">
|
|
|
|
{renderEmoji ? c.name.replace(emojiIcon ? emojiIcon[0] : '', '').trim() : c.name}
|
2021-06-23 22:51:23 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="md:block dark:text-gray-500 flex-shrink-0 hidden col-span-3 font-mono text-sm text-gray-700">
|
2021-08-15 19:13:08 +00:00
|
|
|
{new Date(c.lastModifiedDateTime).toLocaleString('en-US', {
|
|
|
|
year: 'numeric',
|
|
|
|
month: '2-digit',
|
|
|
|
day: '2-digit',
|
|
|
|
hour: '2-digit',
|
|
|
|
minute: '2-digit',
|
|
|
|
hour12: false,
|
2021-06-23 22:51:23 +00:00
|
|
|
})}
|
|
|
|
</div>
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="md:block dark:text-gray-500 flex-shrink-0 hidden col-span-1 font-mono text-sm text-gray-700 truncate">
|
2021-08-23 15:14:08 +00:00
|
|
|
{humanFileSize(c.size)}
|
|
|
|
</div>
|
2021-06-23 22:51:23 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-11-18 22:36:23 +00:00
|
|
|
const Checkbox: FunctionComponent<{
|
|
|
|
checked: 0|1|2, onChange: () => void, title: string, indeterminate?: boolean
|
|
|
|
}> = ({ checked, onChange, title, indeterminate }) => {
|
|
|
|
const ref = useRef<HTMLInputElement>(null)
|
|
|
|
useEffect(() => {
|
|
|
|
if (ref.current) {
|
|
|
|
ref.current.checked = Boolean(checked)
|
|
|
|
if (indeterminate) {
|
|
|
|
ref.current.indeterminate = checked == 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [ref, checked, indeterminate])
|
|
|
|
const handleClick = () => { ref.current ? ref.current.click() : null }
|
|
|
|
|
|
|
|
return (
|
|
|
|
<span
|
|
|
|
title={title}
|
|
|
|
className="hover:bg-gray-300 dark:hover:bg-gray-600 p-2 rounded cursor-pointer"
|
|
|
|
onClick={handleClick}
|
|
|
|
>
|
|
|
|
<input
|
|
|
|
className="form-check-input cursor-pointer"
|
|
|
|
type="checkbox"
|
|
|
|
value={checked ? '1' : ''}
|
|
|
|
ref={ref}
|
|
|
|
aria-label={title}
|
|
|
|
onChange={onChange}
|
|
|
|
/>
|
|
|
|
</span>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-06-23 20:27:51 +00:00
|
|
|
const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) => {
|
2021-06-23 22:51:23 +00:00
|
|
|
const [imageViewerVisible, setImageViewerVisibility] = useState(false)
|
|
|
|
const [activeImageIdx, setActiveImageIdx] = useState(0)
|
2021-11-18 22:36:23 +00:00
|
|
|
const [selected, setSelected] = useState<{[key: string]: boolean}>({})
|
|
|
|
const [totalSelected, setTotalSelected] = useState<0|1|2>(0)
|
2021-06-23 22:51:23 +00:00
|
|
|
|
|
|
|
const router = useRouter()
|
2021-08-23 14:02:06 +00:00
|
|
|
const clipboard = useClipboard()
|
2021-06-23 22:51:23 +00:00
|
|
|
|
2021-06-23 20:27:51 +00:00
|
|
|
const path = queryToPath(query)
|
2021-06-24 21:32:22 +00:00
|
|
|
|
2021-09-05 15:03:27 +00:00
|
|
|
const { data, error, size, setSize } = useProtectedSWRInfinite(path)
|
2021-06-24 21:32:22 +00:00
|
|
|
|
2021-06-25 14:15:00 +00:00
|
|
|
if (error) {
|
|
|
|
return (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="dark:bg-gray-900 p-3 bg-white rounded shadow">
|
2021-08-30 00:35:52 +00:00
|
|
|
{error.message.includes('401') ? <Auth redirect={path} /> : <FourOhFour errorMsg={error.message} />}
|
2021-06-25 14:15:00 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
2021-06-23 22:51:23 +00:00
|
|
|
if (!data) {
|
2021-06-22 13:55:53 +00:00
|
|
|
return (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="dark:bg-gray-900 p-3 bg-white rounded shadow">
|
2021-06-24 23:42:46 +00:00
|
|
|
<Loading loadingText="Loading ..." />
|
2021-06-22 23:15:19 +00:00
|
|
|
</div>
|
2021-06-22 13:55:53 +00:00
|
|
|
)
|
2021-06-23 22:51:23 +00:00
|
|
|
}
|
2021-06-22 13:55:53 +00:00
|
|
|
|
2021-06-23 22:51:23 +00:00
|
|
|
const fileIsImage = (fileName: string) => {
|
|
|
|
const fileExtension = getExtension(fileName)
|
|
|
|
if (hasKey(extensions, fileExtension)) {
|
|
|
|
if (extensions[fileExtension] === preview.image) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-09-05 15:03:27 +00:00
|
|
|
const responses: any[] = data ? [].concat(...data) : []
|
|
|
|
|
|
|
|
const isLoadingInitialData = !data && !error
|
|
|
|
const isLoadingMore = isLoadingInitialData || (size > 0 && data && typeof data[size - 1] === 'undefined')
|
|
|
|
const isEmpty = data?.[0]?.length === 0
|
|
|
|
const isReachingEnd = isEmpty || (data && typeof data[data.length - 1]?.next === 'undefined')
|
|
|
|
const onlyOnePage = data && typeof data[0].next === 'undefined'
|
2021-06-30 11:53:17 +00:00
|
|
|
|
2021-09-05 15:03:27 +00:00
|
|
|
if ('folder' in responses[0]) {
|
2021-06-30 11:53:17 +00:00
|
|
|
// Image preview rendering preparations
|
2021-06-23 22:51:23 +00:00
|
|
|
const imagesInFolder: ImageDecorator[] = []
|
|
|
|
const imageIndexDict: { [key: string]: number } = {}
|
|
|
|
let imageIndex = 0
|
2021-06-30 11:53:17 +00:00
|
|
|
|
|
|
|
// README rendering preparations
|
|
|
|
let renderReadme = false
|
|
|
|
let readmeFile = null
|
|
|
|
|
2021-09-05 15:03:27 +00:00
|
|
|
// Expand list of API returns into flattened file data
|
|
|
|
const children = [].concat(...responses.map(r => r.folder.value))
|
|
|
|
|
|
|
|
children.forEach((c: any) => {
|
2021-06-23 22:51:23 +00:00
|
|
|
if (fileIsImage(c.name)) {
|
|
|
|
imagesInFolder.push({
|
|
|
|
src: c['@microsoft.graph.downloadUrl'],
|
|
|
|
alt: c.name,
|
|
|
|
downloadUrl: c['@microsoft.graph.downloadUrl'],
|
|
|
|
})
|
|
|
|
imageIndexDict[c.id] = imageIndex
|
|
|
|
imageIndex += 1
|
|
|
|
}
|
2021-06-30 11:53:17 +00:00
|
|
|
|
|
|
|
if (c.name.toLowerCase() === 'readme.md') {
|
|
|
|
renderReadme = true
|
|
|
|
readmeFile = c
|
|
|
|
}
|
2021-06-23 22:51:23 +00:00
|
|
|
})
|
|
|
|
|
2021-11-18 22:36:23 +00:00
|
|
|
// File selection
|
|
|
|
const genTotalSelected = (selected: {[key: string]: boolean}) => {
|
|
|
|
const selectInfo = children.map((c :any) => Boolean(selected[c.id]))
|
|
|
|
const [hasT, hasF] = [selectInfo.some(i => i), selectInfo.some(i => !i)]
|
|
|
|
console.log(hasT, hasF)
|
|
|
|
return hasT && hasF ? 1 : (!hasF ? 2 : 0)
|
|
|
|
}
|
|
|
|
const toggleItemSelected = (id: string) => {
|
|
|
|
let val
|
|
|
|
if (selected[id]) {
|
|
|
|
val = {...selected}
|
|
|
|
delete val[id]
|
|
|
|
} else {
|
|
|
|
val = {...selected, [id]: true}
|
|
|
|
}
|
|
|
|
setSelected(val)
|
|
|
|
setTotalSelected(genTotalSelected(val))
|
|
|
|
}
|
|
|
|
const toggleTotalSelected = () => {
|
|
|
|
if (genTotalSelected(selected) == 2) {
|
|
|
|
setSelected({})
|
|
|
|
setTotalSelected(0)
|
|
|
|
} else {
|
|
|
|
setSelected(Object.fromEntries(children.map((c :any) => [c.id, true])))
|
|
|
|
setTotalSelected(2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-18 23:28:05 +00:00
|
|
|
// Selected file download
|
|
|
|
const handleDownloadSelected = () => {
|
|
|
|
const folderName = path.substr(path.lastIndexOf('/') + 1)
|
|
|
|
const folder = folderName ? folderName : undefined
|
|
|
|
const files = children.filter((c: any) => selected[c.id])
|
|
|
|
.map((c: any) => ({ name: c.name, url: c['@microsoft.graph.downloadUrl'] }))
|
|
|
|
saveFiles(files, folder)
|
|
|
|
}
|
|
|
|
|
2021-06-23 22:51:23 +00:00
|
|
|
return (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="dark:bg-gray-900 dark:text-gray-100 bg-white rounded shadow">
|
|
|
|
<div className="dark:border-gray-700 grid items-center grid-cols-12 p-3 space-x-2 border-b border-gray-200">
|
2021-11-18 20:13:19 +00:00
|
|
|
<div className="md:col-span-6 col-span-12 font-bold">Name</div>
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="md:block hidden col-span-3 font-bold">Last Modified</div>
|
|
|
|
<div className="md:block hidden font-bold">Size</div>
|
|
|
|
<div className="md:block hidden font-bold">Actions</div>
|
2021-11-18 20:13:19 +00:00
|
|
|
<div className="md:block hidden font-bold">
|
|
|
|
<div className="md:flex dark:text-gray-400 hidden p-1 text-gray-700">
|
2021-11-18 22:36:23 +00:00
|
|
|
<Checkbox
|
|
|
|
checked={totalSelected}
|
|
|
|
onChange={toggleTotalSelected}
|
|
|
|
indeterminate={true}
|
|
|
|
title={"Select files"}
|
|
|
|
/>
|
2021-11-18 23:28:05 +00:00
|
|
|
{totalSelected ? (
|
|
|
|
<span
|
|
|
|
title="Download selected files"
|
|
|
|
className="hover:bg-gray-300 dark:hover:bg-gray-600 p-2 rounded cursor-pointer"
|
|
|
|
onClick={handleDownloadSelected}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'arrow-alt-circle-down']} />
|
|
|
|
</span>
|
|
|
|
) : ''}
|
2021-11-18 20:13:19 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2021-06-23 22:51:23 +00:00
|
|
|
</div>
|
2021-08-29 21:31:42 +00:00
|
|
|
|
|
|
|
<Toaster
|
|
|
|
toastOptions={{
|
|
|
|
style: {
|
|
|
|
background: '#316C23',
|
|
|
|
color: '#ffffff',
|
|
|
|
},
|
|
|
|
}}
|
|
|
|
/>
|
2021-06-23 22:51:23 +00:00
|
|
|
|
|
|
|
{imagesInFolder.length !== 0 && (
|
|
|
|
<ReactViewer
|
2021-06-30 11:34:08 +00:00
|
|
|
zIndex={99}
|
2021-06-23 22:51:23 +00:00
|
|
|
visible={imageViewerVisible}
|
|
|
|
activeIndex={activeImageIdx}
|
|
|
|
images={imagesInFolder}
|
|
|
|
drag={false}
|
|
|
|
rotatable={false}
|
|
|
|
noClose={true}
|
2021-06-25 17:47:57 +00:00
|
|
|
scalable={false}
|
2021-06-29 20:00:05 +00:00
|
|
|
zoomSpeed={0.2}
|
2021-06-23 22:51:23 +00:00
|
|
|
downloadable={true}
|
|
|
|
downloadInNewWindow={true}
|
|
|
|
onMaskClick={() => {
|
|
|
|
setImageViewerVisibility(false)
|
|
|
|
}}
|
2021-06-25 17:47:57 +00:00
|
|
|
customToolbar={toolbars => {
|
2021-06-25 18:22:22 +00:00
|
|
|
toolbars[0].render = <FontAwesomeIcon icon="plus" />
|
|
|
|
toolbars[1].render = <FontAwesomeIcon icon="minus" />
|
|
|
|
toolbars[2].render = <FontAwesomeIcon icon="arrow-left" />
|
2021-06-29 20:00:05 +00:00
|
|
|
toolbars[3].render = <FontAwesomeIcon icon="undo" />
|
2021-06-25 18:22:22 +00:00
|
|
|
toolbars[4].render = <FontAwesomeIcon icon="arrow-right" />
|
|
|
|
toolbars[9].render = <FontAwesomeIcon icon="download" />
|
2021-06-25 17:47:57 +00:00
|
|
|
return toolbars.concat([
|
|
|
|
{
|
|
|
|
key: 'copy',
|
2021-08-29 16:14:17 +00:00
|
|
|
render: <FontAwesomeIcon icon={['fas', 'copy']} />,
|
2021-06-25 17:47:57 +00:00
|
|
|
onClick: i => {
|
2021-08-23 14:02:06 +00:00
|
|
|
clipboard.copy(i.alt ? `${getBaseUrl()}/api?path=${path + '/' + i.alt}&raw=true` : '')
|
2021-06-25 18:22:22 +00:00
|
|
|
toast.success('Copied image permanent link to clipboard.')
|
2021-06-25 17:47:57 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
])
|
|
|
|
}}
|
2021-06-23 22:51:23 +00:00
|
|
|
/>
|
|
|
|
)}
|
|
|
|
|
2021-09-05 15:03:27 +00:00
|
|
|
{children.map((c: any) => (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="hover:bg-gray-100 dark:hover:bg-gray-850 grid grid-cols-12" key={c.id}>
|
2021-08-29 16:14:17 +00:00
|
|
|
<div
|
2021-11-18 20:13:19 +00:00
|
|
|
className="col-span-10"
|
2021-08-29 16:14:17 +00:00
|
|
|
onClick={e => {
|
|
|
|
e.preventDefault()
|
|
|
|
|
|
|
|
if (!c.folder && fileIsImage(c.name)) {
|
|
|
|
setActiveImageIdx(imageIndexDict[c.id])
|
|
|
|
setImageViewerVisibility(true)
|
|
|
|
} else {
|
|
|
|
router.push(`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`)
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<FileListItem fileContent={c} />
|
|
|
|
</div>
|
|
|
|
{c.folder ? (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="md:flex dark:text-gray-400 hidden p-1 text-gray-700">
|
2021-08-29 16:14:17 +00:00
|
|
|
<span
|
|
|
|
title="Copy folder permalink"
|
2021-09-04 14:15:09 +00:00
|
|
|
className="hover:bg-gray-300 dark:hover:bg-gray-600 p-2 rounded cursor-pointer"
|
2021-08-29 16:14:17 +00:00
|
|
|
onClick={() => {
|
|
|
|
clipboard.copy(`${getBaseUrl()}${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`)
|
2021-08-29 21:31:42 +00:00
|
|
|
toast.success('Copied folder permalink.')
|
2021-08-29 16:14:17 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'copy']} />
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
) : (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="md:flex dark:text-gray-400 hidden p-1 text-gray-700">
|
2021-08-29 16:14:17 +00:00
|
|
|
<span
|
|
|
|
title="Copy raw file permalink"
|
2021-09-04 14:15:09 +00:00
|
|
|
className="hover:bg-gray-300 dark:hover:bg-gray-600 p-2 rounded cursor-pointer"
|
2021-08-29 16:14:17 +00:00
|
|
|
onClick={() => {
|
|
|
|
clipboard.copy(`${getBaseUrl()}/api?path=${path === '/' ? '' : path}/${c.name}&raw=true`)
|
2021-08-29 21:31:42 +00:00
|
|
|
toast.success('Copied raw file permalink.')
|
2021-08-29 16:14:17 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'copy']} />
|
|
|
|
</span>
|
|
|
|
<a
|
|
|
|
title="Download file"
|
2021-09-04 14:15:09 +00:00
|
|
|
className="hover:bg-gray-300 dark:hover:bg-gray-600 p-2 rounded cursor-pointer"
|
2021-08-29 16:14:17 +00:00
|
|
|
href={c['@microsoft.graph.downloadUrl']}
|
|
|
|
>
|
|
|
|
<FontAwesomeIcon icon={['far', 'arrow-alt-circle-down']} />
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
)}
|
2021-11-18 20:13:19 +00:00
|
|
|
<div className="md:flex dark:text-gray-400 hidden p-1 text-gray-700">
|
2021-11-18 22:36:23 +00:00
|
|
|
<Checkbox
|
|
|
|
checked={selected[c.id] ? 2 : 0}
|
|
|
|
onChange={() => toggleItemSelected(c.id)}
|
|
|
|
title={"Select file"}
|
|
|
|
/>
|
2021-11-18 20:13:19 +00:00
|
|
|
</div>
|
2021-06-23 22:51:23 +00:00
|
|
|
</div>
|
|
|
|
))}
|
2021-06-30 11:53:17 +00:00
|
|
|
|
2021-09-05 15:03:27 +00:00
|
|
|
{!onlyOnePage && (
|
|
|
|
<div>
|
2021-09-05 15:09:24 +00:00
|
|
|
<div className="dark:border-gray-700 p-3 font-mono text-sm text-center text-gray-400 border-b border-gray-200">
|
2021-09-05 15:03:27 +00:00
|
|
|
- showing {size} page{size > 1 ? 's' : ''} of {isLoadingMore ? '...' : children.length} files -
|
|
|
|
</div>
|
|
|
|
<button
|
|
|
|
className={`flex items-center justify-center w-full p-3 space-x-2 ${
|
2021-09-05 15:09:24 +00:00
|
|
|
isLoadingMore || isReachingEnd ? 'opacity-60' : 'hover:bg-gray-100 dark:hover:bg-gray-850'
|
2021-09-05 15:03:27 +00:00
|
|
|
}`}
|
|
|
|
onClick={() => setSize(size + 1)}
|
|
|
|
disabled={isLoadingMore || isReachingEnd}
|
|
|
|
>
|
|
|
|
{isLoadingMore ? (
|
|
|
|
<>
|
|
|
|
<span>Loading ...</span>{' '}
|
|
|
|
<svg
|
|
|
|
className="animate-spin w-5 h-5 mr-3 -ml-1"
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
fill="none"
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
>
|
|
|
|
<circle
|
|
|
|
className="opacity-25"
|
|
|
|
cx="12"
|
|
|
|
cy="12"
|
|
|
|
r="10"
|
|
|
|
stroke="currentColor"
|
|
|
|
strokeWidth="4"
|
|
|
|
></circle>
|
|
|
|
<path
|
|
|
|
className="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>
|
|
|
|
</>
|
|
|
|
) : isReachingEnd ? (
|
|
|
|
<span>No more files</span>
|
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
<span>Load more</span>
|
|
|
|
<FontAwesomeIcon icon="chevron-circle-down" />
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
2021-06-30 11:53:17 +00:00
|
|
|
{renderReadme && (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="dark:border-gray-700 border-t">
|
2021-08-31 12:59:31 +00:00
|
|
|
<MarkdownPreview file={readmeFile} path={path} standalone={false} />
|
2021-06-30 11:53:17 +00:00
|
|
|
</div>
|
|
|
|
)}
|
2021-06-22 23:15:19 +00:00
|
|
|
</div>
|
2021-06-23 22:51:23 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-09-05 15:03:27 +00:00
|
|
|
if ('file' in responses[0] && responses.length === 1) {
|
|
|
|
const { file } = responses[0]
|
|
|
|
const downloadUrl = file['@microsoft.graph.downloadUrl']
|
|
|
|
const fileName = file.name
|
2021-06-23 22:51:23 +00:00
|
|
|
const fileExtension = fileName.slice(((fileName.lastIndexOf('.') - 1) >>> 0) + 2).toLowerCase()
|
|
|
|
|
|
|
|
if (hasKey(extensions, fileExtension)) {
|
|
|
|
switch (extensions[fileExtension]) {
|
|
|
|
case preview.image:
|
2021-06-25 18:22:22 +00:00
|
|
|
return (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="w-full p-3 bg-white rounded shadow">
|
2021-06-25 18:22:22 +00:00
|
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
|
|
<img className="mx-auto" src={downloadUrl} alt={fileName} />
|
|
|
|
</div>
|
|
|
|
)
|
2021-06-23 22:51:23 +00:00
|
|
|
|
2021-06-24 13:54:59 +00:00
|
|
|
case preview.text:
|
2021-09-05 15:03:27 +00:00
|
|
|
return <TextPreview file={file} />
|
2021-06-24 13:54:59 +00:00
|
|
|
|
|
|
|
case preview.code:
|
2021-09-05 15:03:27 +00:00
|
|
|
return <CodePreview file={file} />
|
2021-06-24 13:54:59 +00:00
|
|
|
|
|
|
|
case preview.markdown:
|
2021-09-05 15:03:27 +00:00
|
|
|
return <MarkdownPreview file={file} path={path} />
|
2021-06-24 13:54:59 +00:00
|
|
|
|
|
|
|
case preview.video:
|
2021-09-05 15:03:27 +00:00
|
|
|
return <VideoPreview file={file} />
|
2021-06-24 23:47:57 +00:00
|
|
|
|
2021-06-24 13:54:59 +00:00
|
|
|
case preview.audio:
|
2021-09-05 15:03:27 +00:00
|
|
|
return <AudioPreview file={file} />
|
2021-06-24 13:54:59 +00:00
|
|
|
|
|
|
|
case preview.pdf:
|
2021-09-05 15:03:27 +00:00
|
|
|
return <PDFPreview file={file} />
|
2021-06-24 13:54:59 +00:00
|
|
|
|
2021-06-29 15:20:35 +00:00
|
|
|
case preview.office:
|
2021-09-05 15:03:27 +00:00
|
|
|
return <OfficePreview file={file} />
|
2021-06-29 15:20:35 +00:00
|
|
|
|
2021-10-05 21:28:40 +00:00
|
|
|
case preview.epub:
|
|
|
|
return <EPUBPreview file={file} />
|
|
|
|
|
2021-06-23 22:51:23 +00:00
|
|
|
default:
|
2021-09-04 14:15:09 +00:00
|
|
|
return <div className="dark:bg-gray-900 bg-white rounded shadow">{fileName}</div>
|
2021-06-23 22:51:23 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-29 20:00:05 +00:00
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="dark:bg-gray-900 p-3 bg-white rounded shadow">
|
2021-06-29 20:00:05 +00:00
|
|
|
<FourOhFour
|
2021-09-05 15:03:27 +00:00
|
|
|
errorMsg={`Preview for file ${fileName} is not available, download directly with the button below.`}
|
2021-06-29 20:00:05 +00:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div className="mt-4">
|
|
|
|
<DownloadBtn downloadUrl={downloadUrl} />
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
)
|
2021-06-23 22:51:23 +00:00
|
|
|
}
|
|
|
|
|
2021-06-25 14:15:00 +00:00
|
|
|
return (
|
2021-09-04 14:15:09 +00:00
|
|
|
<div className="dark:bg-gray-900 p-3 bg-white rounded shadow">
|
2021-09-05 15:03:27 +00:00
|
|
|
<FourOhFour errorMsg={`Cannot preview ${path}`} />
|
2021-06-25 14:15:00 +00:00
|
|
|
</div>
|
|
|
|
)
|
2021-06-22 13:55:53 +00:00
|
|
|
}
|
|
|
|
export default FileListing
|