import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import toast, { Toaster } from 'react-hot-toast' import emojiRegex from 'emoji-regex' import { useClipboard } from 'use-clipboard-copy' import { ParsedUrlQuery } from 'querystring' import { FunctionComponent, useState } from 'react' import { ImageDecorator } from 'react-viewer/lib/ViewerProps' import { useRouter } from 'next/router' import dynamic from 'next/dynamic' import { getExtension, getFileIcon, hasKey } from '../utils/getFileIcon' import { extensions, preview } from '../utils/getPreviewType' import { getBaseUrl, useStaleSWR } from '../utils/tools' import { VideoPreview } from './previews/VideoPreview' import { AudioPreview } from './previews/AudioPreview' import Loading from './Loading' import FourOhFour from './FourOhFour' import Auth from './Auth' import TextPreview from './previews/TextPreview' import MarkdownPreview from './previews/MarkdownPreview' import CodePreview from './previews/CodePreview' import OfficePreview from './previews/OfficePreview' import DownloadBtn from './DownloadBtn' // Disabling SSR for some previews (image gallery view, and PDF view) const ReactViewer = dynamic(() => import('react-viewer'), { ssr: false }) const PDFPreview = dynamic(() => import('./previews/PDFPreview'), { ssr: false }) /** * 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 */ 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` } /** * Convert url query into path string * * @param query Url query property * @returns Path string */ const queryToPath = (query?: ParsedUrlQuery) => { if (query) { const { path } = query if (!path) return '/' if (typeof path === 'string') return `/${encodeURIComponent(path)}` return `/${path.map(p => encodeURIComponent(p)).join('/')}` } return '/' } const FileListItem: FunctionComponent<{ fileContent: { id: string; name: string; size: number; file: Object; lastModifiedDateTime: string } }> = ({ fileContent: c }) => { const emojiIcon = emojiRegex().exec(c.name) const renderEmoji = emojiIcon && !emojiIcon.index return (
{/*
{c.file ? c.file.mimeType : 'folder'}
*/}
{renderEmoji ? ( {emojiIcon ? emojiIcon[0] : '📁'} ) : ( )}
{renderEmoji ? c.name.replace(emojiIcon ? emojiIcon[0] : '', '').trim() : c.name}
{new Date(c.lastModifiedDateTime).toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false, })}
{humanFileSize(c.size)}
) } const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) => { const [imageViewerVisible, setImageViewerVisibility] = useState(false) const [activeImageIdx, setActiveImageIdx] = useState(0) const router = useRouter() const clipboard = useClipboard() const path = queryToPath(query) const { data, error } = useStaleSWR(`/api?path=${path}`, path) if (error) { return (
{error.message.includes('401') ? : }
) } if (!data) { return (
) } const resp = data.data const fileIsImage = (fileName: string) => { const fileExtension = getExtension(fileName) if (hasKey(extensions, fileExtension)) { if (extensions[fileExtension] === preview.image) { return true } } return false } if ('folder' in resp) { const { children } = resp // Image preview rendering preparations const imagesInFolder: ImageDecorator[] = [] const imageIndexDict: { [key: string]: number } = {} let imageIndex = 0 // README rendering preparations let renderReadme = false let readmeFile = null children.forEach((c: any) => { 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 } if (c.name.toLowerCase() === 'readme.md') { renderReadme = true readmeFile = c } }) return (
Name
Last Modified
Size
Actions
{imagesInFolder.length !== 0 && ( { setImageViewerVisibility(false) }} customToolbar={toolbars => { toolbars[0].render = toolbars[1].render = toolbars[2].render = toolbars[3].render = toolbars[4].render = toolbars[9].render = return toolbars.concat([ { key: 'copy', render: , onClick: i => { clipboard.copy(i.alt ? `${getBaseUrl()}/api?path=${path + '/' + i.alt}&raw=true` : '') toast.success('Copied image permanent link to clipboard.') }, }, ]) }} /> )} {children.map((c: any) => (
{ e.preventDefault() if (!c.folder && fileIsImage(c.name)) { setActiveImageIdx(imageIndexDict[c.id]) setImageViewerVisibility(true) } else { router.push(`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`) } }} >
{c.folder ? (
{ clipboard.copy(`${getBaseUrl()}${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`) toast.success('Copied folder permalink.') }} >
) : (
{ clipboard.copy(`${getBaseUrl()}/api?path=${path === '/' ? '' : path}/${c.name}&raw=true`) toast.success('Copied raw file permalink.') }} >
)}
))} {renderReadme && (
)}
) } if ('file' in resp) { const downloadUrl = resp['@microsoft.graph.downloadUrl'] const fileName = resp.name const fileExtension = fileName.slice(((fileName.lastIndexOf('.') - 1) >>> 0) + 2).toLowerCase() if (hasKey(extensions, fileExtension)) { switch (extensions[fileExtension]) { case preview.image: return (
{/* eslint-disable-next-line @next/next/no-img-element */} {fileName}
) case preview.text: return case preview.code: return case preview.markdown: return case preview.video: return case preview.audio: return case preview.pdf: return case preview.office: return default: return
{fileName}
} } return ( <>
) } return (
) } export default FileListing